闭包是否违反了函数式编程范式?

kwa*_*ick 24 closures haskell functional-programming

功能编程"避免状态和可变数据".

闭包通过绑定它们的词法环境来隐藏状态,因此关闭它们的自由变量.

如果Haskell支持闭包,它是如何纯粹功能的?他们不打破参考透明度吗?

ami*_*dfv 22

在Haskell中,闭包有自由变量的方式与数学中你可以写的相同f x = x^2- 它不会改变状态.

我会说Haskell避免了可变状态.


Lui*_*las 17

闭包不是违规,因为Haskell中的所有绑定都是不可变的.什么闭包真正意味着带有自由变量的lambda不表示一个独特的函数; 它将表示不同的函数,具体取决于每次评估时对其自由变量有效的绑定.例如:

makeClosure :: Num a => a -> a -> a
makeClosure x = \y -> x+y
Run Code Online (Sandbox Code Playgroud)

表达式makeClosure 5评估的函数不同于makeClosure 6; 更重要的是,makeClosure 5程序不同部分的两次出现评估相同的功能,如同makeClosure (2+3)或类似; 即,我们有参考透明度(用等于代替表达式保留了程序的含义).

在你提到的引用中,你似乎对"州"的含义感到困惑.在这种情况下,国家意味着可变数据; 闭包绝对可以"隐藏"数据,但在Haskell中,这些数据不可变,因此它不会隐藏状态.与此形成对比的是,根据我的经验,Java程序员经常说在有问题的数据不可变的情况下,类实例"隐藏状态",例如,private final从构造函数分配给实例字段; 它们的真正含义是类(和闭包)封装数据.


nom*_*olo 12

不,闭包很好并且不会在Haskell中引起问题,因为闭包会关闭自由变量的.您可以隐藏其他语言中的闭包状态的原因是您关闭了引用.如您所知,在Javascript中:

var x = 1;
var f = function(y) { return y + x; }
f(2)  // => 3
x = 2;
f(2)  // => 4
Run Code Online (Sandbox Code Playgroud)

你可以通过IORef在Haskell中使用s 来实际建模:

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

这没关系,因为函数f有类型Int -> IO Int而不是Int -> Int.换句话说,f绑定到相同的操作,但是当执行时,相同的操作可能每次都返回不同的结果.