Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

Фактически вы можете моделировать это, используя IORef в 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 привязано к одному и тому же действию, но при выполнении того же действия каждый раз может возвращать разные результаты.

Ответ 4

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

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