Многие современные языки программирования поддерживают некоторую концепцию замыкания , то есть кусок кода (блок или функцию), который
- Может рассматриваться как значение и, следовательно, храниться в переменной, передаваться различным частям кода, определяться в одной части программы и вызываться в совершенно другой части той же программы.
- Может захватывать переменные из контекста, в котором они определены, и получать к ним доступ при последующем вызове (возможно, в совершенно ином контексте).
Вот пример замыкания, написанного на Scala:
def filterList(xs: List[Int], lowerBound: Int): List[Int] =
xs.filter(x => x >= lowerBound)
Литерал функции x => x >= lowerBound
содержит свободную переменную lowerBound
, которая закрыта (связана) аргументом функции filterList
с тем же именем. Закрытие передается методу библиотеки filter
, который может вызывать его повторно как обычную функцию.
Я читал много вопросов и ответов на этом сайте, и, насколько я понимаю, термин « закрытие» часто автоматически ассоциируется с функциональным программированием и функциональным стилем программирования.
Определение функции программирования в Википедии гласит:
В информатике функциональное программирование - это парадигма программирования, которая рассматривает вычисления как оценку математических функций и избегает состояния и изменчивых данных. Он подчеркивает применение функций, в отличие от императивного стиля программирования, который подчеркивает изменения в состоянии.
и далее
[...] в функциональном коде выходное значение функции зависит только от аргументов, которые вводятся в функцию [...]. Устранение побочных эффектов может значительно облегчить понимание и прогнозирование поведения программы, что является одним из ключевых факторов развития функционального программирования.
С другой стороны, многие конструкции замыкания, предоставляемые языками программирования, позволяют замыканию захватывать нелокальные переменные и изменять их при вызове замыкания, создавая тем самым побочный эффект для среды, в которой они были определены.
В этом случае замыкания реализуют первую идею функционального программирования (функции - это объекты первого класса, которые можно перемещать, как и другие значения), но игнорируют вторую идею (избегая побочных эффектов).
Это использование замыканий с побочными эффектами считается функциональным стилем или замыкания считаются более общей конструкцией, которая может использоваться как для функционального, так и для нефункционального стиля программирования? Есть ли литература на эту тему?
ВАЖНАЯ ЗАМЕТКА
Я не подвергаю сомнению полезность побочных эффектов или наличия закрытий с побочными эффектами. Кроме того, меня не интересует обсуждение преимуществ / недостатков укупорочных средств с побочными эффектами или без них.
Мне только интересно узнать, считается ли использование таких замыканий функциональным стилем сторонником функционального программирования или, наоборот, их использование не рекомендуется при использовании функционального стиля.
источник
Ответы:
Нет; определение функциональной парадигмы - отсутствие состояния и косвенное отсутствие побочных эффектов. Речь идет не о функциях высокого порядка, замыканиях, манипулировании списком с поддержкой языков или других языковых особенностях ...
Название функционального программирования происходит от математического понятия функций - повторные вызовы на одном и том же входе всегда дают один и тот же выход - нулевую функцию. Это может быть достигнуто только в том случае, если данные неизменны . Чтобы облегчить разработку, функции стали изменяемыми (функции меняются, данные по-прежнему неизменны) и, таким образом, понятие функций более высокого порядка (функционалы в математике, например, производные) - функция, которая принимает в качестве входных данных другую функцию. Для возможности переноса и передачи функций в качестве аргументов были приняты первоклассные функции ; после этого, чтобы еще больше повысить производительность, появились пробки .
Это, конечно, очень упрощенный вид.
источник
map
Например, возьмем функцию, которая применяет ее к списку и возвращает список результатов.map
не изменяет ни один из своих аргументов, он не меняет поведение функции, которую он принимает в качестве аргумента, но это определенно функция высшего порядка - если вы примените ее частично, только с помощью параметра функции, вы построите новая функция, которая работает со списком, но мутации еще не произошло.Нет. «Функциональный стиль» подразумевает программирование без побочных эффектов.
Чтобы понять почему, взгляните на запись Эрика Липперта в блоге о
ForEach<T>
методе расширения и о том , почему Microsoft не включила такой метод последовательности в Linq :источник
ParallelQuery<T>.ForAll(...)
. Реализация такойIEnumerable<T>.ForEach(...)
чрезвычайно полезна для отладкиForAll
заявления (заменитьForAll
сForEach
и удалить ,AsParallel()
и вы можете гораздо легче пошагово / отладить)Функциональное программирование наверняка переводит функции первого класса на следующий концептуальный уровень, но объявление анонимных функций или передача функций другим функциям не обязательно является функцией функционального программирования. В Си все было целым числом. Число, указатель на данные, указатель на функцию ... все просто целые числа. Вы можете передавать указатели функций другим функциям, составлять списки указателей функций ... Черт, если вы работаете на ассемблере, функции - это просто адреса в памяти, где хранятся блоки машинных инструкций. Присвоение имени функции является дополнительной нагрузкой для людей, которым нужен компилятор для написания кода. Таким образом, функции были «первоклассными» в этом смысле на совершенно нефункциональном языке.
Если единственное, что вы делаете, это вычисляете математические формулы в REPL, то вы можете быть функционально чисты с вашим языком. Но у большинства бизнес-программ есть побочные эффекты. Потеря денег при ожидании завершения долгосрочной программы является побочным эффектом. Выполнение любых внешних действий: запись в файл, обновление базы данных, регистрация событий по порядку и т. Д. Требуют изменения состояния. Мы могли бы обсудить, действительно ли изменено состояние, если вы заключите эти действия в неизменяемые обертки, которые отталкивают побочные эффекты, так что вашему коду не нужно беспокоиться о них. Но это все равно, что обсуждать, шумит ли дерево, если оно падает в лесу, где его никто не слышит. Дело в том, что дерево встало вертикально и упало на землю. Состояние будет изменено, когда что-то будет сделано, даже если только сообщать, что это сделано.
Таким образом, мы остаемся со шкалой функциональной чистоты, не черно-белой, а с оттенками серого. И в этом масштабе, чем меньше побочных эффектов, тем меньше изменчивость, тем лучше (более функционально).
Если вам абсолютно необходим побочный эффект или изменяемое состояние в вашем другом функциональном коде, вы стремитесь инкапсулировать его или его из остальной части вашей программы как можно лучше. Использование замыкания (или чего-либо еще) для введения побочных эффектов или изменяемого состояния в иные чистые функции является противоположностью функционального программирования. Единственное исключение может быть, если закрытие было наиболее эффективным способом инкапсулировать побочные эффекты из кода, которому он передается. Это все еще не «функциональное программирование», но это может быть шкаф, который вы можете получить в определенных ситуациях.
источник