Побочные эффекты в закрытии, они все еще чисто функциональны?

Будучи относительно новым для функционального программирования, я трачу много энергии на размышления: "Это функциональный способ сделать что-то?" Очевидно, что рекурсия против итерации довольно проста, и очевидно, что рекурсия - это функциональный способ делать вещи. Но, например, возьмите закрытие. Я узнал о закрытии с помощью Lisp, и я понимаю, что замыкания - это комбинация функции и среды (звучит так же, как состояние и поведение). Например:

(let ((x 1))
           (defun doubleX()
              (setf x (* x 2))))

Здесь мы имеем функцию doubleX, которая была определена в среде переменной x. Мы могли бы передать эту функцию другим функциям, а затем вызвать ее, и она все равно сможет ссылаться на переменную x. Функция может продолжать ссылаться на эту переменную, даже если она вызывается вне среды, где определена переменная. Многие из примеров, которые я видел при закрытии, выглядят так. Если setf используется для изменения значения лексической переменной. Это меня смущает, потому что:

1.) Я думал, что setf был злым. В основном потому, что он вызывает побочные эффекты и, по-видимому, они также злы.

2.) Действительно ли это "функционально"? Похоже, это просто способ сохранить глобальное состояние, и я думал, что функциональные языки не имеют гражданства.

Возможно, я просто не понимаю закрытия. Может кто-нибудь помочь мне?

Ответы

Ответ 1

Вы правы, использование закрытий для управления состоянием не является чисто функциональным. Lisp позволяет вам программировать в функциональном стиле, но это не заставляет вас. Я действительно предпочитаю этот подход, потому что он позволяет мне нанести прагматичный баланс между чисто функциональным и удобством изменения состояния.

Что вы можете попробовать - написать что-то, что кажется функциональным извне, но сохраняет работоспособность внутреннего изменчивого состояния. Отличным примером этого является memoization, в котором вы сохраняете запись обо всех предыдущих вызовах для ускорения функций, таких как fibonacci, но поскольку функция всегда возвращает один и тот же вывод для одного и того же ввода и не изменяет никакого внешнего состояния, его можно считать быть функциональным снаружи.

Ответ 2

Закрытие - это объекты с бедными людьми (и наоборот), см.

Когда использовать закрытие?

и мой ответ. Поэтому, если вы намерены использовать побочные эффекты для управления состоянием в своем приложении, отличном от OO, закрытие-over-mutable-state действительно является простым способом сделать это. Неизменяемые альтернативы "менее злые", но 99,9% языков предлагают изменчивое состояние, и они не могут ошибаться.:) Mutable state ценен при использовании разумно, но он может быть особенно подвержен ошибкам при использовании с закрытием и захватом, как видно здесь.

О лямбдах, захвате и изменчивости

В любом случае, я думаю, что причина, по которой вы видите "столько примеров, подобных этому", заключается в том, что одним из наиболее распространенных способов объяснения поведения замыканий является показать такой крошечный пример, когда замыкание захватывает изменчивое и, следовательно, становится мини-stateful-объектом, который инкапсулирует некоторое изменчивое состояние. Это отличный пример, который поможет вам понять последствия жизни и побочные эффекты конструкции, но это не одобрение, чтобы использовать эту конструкцию повсюду.

В большинстве случаев с закрытием вы просто закрываете значения или неизменяемое состояние и "не замечаете", что вы это делаете.

Ответ 3

Общие Lisp и схема не являются чисто функциональными. Clojure в основном функциональный, но все же не чисто. Haskell - единственный язык, который я знаю, который является чисто функциональным, я даже не могу назвать имя другого.

Истина заключается в том, что работать в чисто функциональной среде очень сложно (пойдите, изучите Haskell и попробуйте что-то программировать на нем). Таким образом, все эти языки функционального программирования действительно то, что они делают, это возможность функционального программирования, но не принудительное исполнение. Функциональное программирование очень мощное, поэтому используйте его, когда можете, и когда вы этого не сделаете.

Что-то важное, что нужно знать с возрастом, что все, что функционал парализуемо, поэтому имеет смысл избежать побочных эффектов или иметь как можно меньше подмножество вашей программы.