Являются ли замыкания нарушением парадигмы функционального программирования? - PullRequest
23 голосов
/ 23 февраля 2012

Функциональное программирование "избегает состояния и изменяемых данных".

Замыкания скрывают состояние, связывая их лексическое окружение и, таким образом, закрываются над их свободными переменными .

Как Haskell является чисто функциональным, если он поддерживает замыкания?Разве они не нарушают ссылочную прозрачность?

Ответы [ 4 ]

22 голосов
/ 23 февраля 2012

В Haskell у замыканий есть свободные переменные так же, как в математике вы можете написать f x = x^2 - это не изменяет состояние.

Я бы сказал, что Haskell избегает изменяемого состояния.

16 голосов
/ 23 февраля 2012

Закрытия не являются нарушением, потому что все привязки в Haskell неизменны. Что на самом деле означает замыкание, так это то, что лямбда со свободными переменными не обозначает одну уникальную функцию; он будет обозначать различные функции в зависимости от привязок, которые действуют для его свободных переменных при каждой оценке. E.g.:

makeClosure :: Num a => a -> a -> a
makeClosure x = \y -> x+y

Выражение makeClosure 5 оценивается как функция, отличная от makeClosure 6; и что еще более важно, два вхождения makeClosure 5 в разных частях программы оцениваются для одной и той же функции , как и для makeClosure (2+3) или аналогичной; то есть, у нас ссылочная прозрачность (замена выражений на их равные сохраняет смысл программы).

Вы, кажется, смущены значением слова "состояние" в упомянутой вами цитате. Состояние в этом контексте означает изменчивые данные; замыкания могут определенно «скрывать» данные, но в Haskell эти данные не являются изменяемыми, поэтому они не скрывают состояние. В противоположность этому, по моему опыту, Java-программисты часто говорят, что экземпляр класса «скрывает состояние» в тех случаях, когда данные не являются изменяемыми, например, присваиваются полю экземпляра private final из конструктора; на самом деле они имеют в виду, что классы (и замыкания) инкапсулируют данные.

12 голосов
/ 24 февраля 2012

Нет, замыкания в порядке и не вызывают проблем в Haskell, потому что замыкание закрывает значения свободных переменных. Причина, по которой вы можете скрыть состояние за замыканиями на других языках, заключается в том, что вы закрываете ссылку . Как известно, в Javascript:

var x = 1;
var f = function(y) { return y + x; }
f(2)  // => 3
x = 2;
f(2)  // => 4

Вы можете смоделировать это, используя IORef s в Haskell:

main = do
  x <- newIORef 1
  let f y = do x' <- readIORef x
               return (y + x')
  r1 <- f 2
  writeIORef x 2
  r2 <- f 2

Это нормально, потому что функция f имеет тип Int -> IO Int вместо Int -> Int. Другими словами, f связан с одним и тем же действием, но при выполнении это одно и то же действие может каждый раз возвращать разные результаты.

2 голосов
/ 27 июля 2012

Мое работающее определение "функционального программирования" состоит в том, что если вы добавляете одну и ту же вещь (и), вы всегда получаете одну и ту же вещь (и).

Замыкания не нарушают это определение в Haskell (попробуйте и придумайте замыкание, которое делает :)), поэтому замыкания не нарушают парадигму FP.

...