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

时间:2012-02-23 18:43:24

标签: haskell functional-programming closures

功能编程“避免状态和可变数据”。

Closures通过绑定它们的词汇环境来隐藏状态,因此关闭了它们的免费变量

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

4 个答案:

答案 0 :(得分:22)

在Haskell中,闭包有自由变量,就像在数学中你可以写f x = x^2一样 - 它不会改变状态。

我想说Haskell避免了可变的状态。

答案 1 :(得分:16)

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

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

表达式makeClosure 5的计算结果与makeClosure 6不同;更重要的是,程序的不同部分中出现makeClosure 5两次{strong>评估为相同的函数,makeClosure (2+3)或类似函数;即,我们有引用透明度(用等号替换表达式保留了程序的含义)。

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

答案 2 :(得分:12)

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

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

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

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绑定到同一个操作,但执行时每次都会返回不同的结果。

答案 3 :(得分:2)

我的工作人员对“函数式编程”的定义是,如果你把相同的东西放进去,你总是得到相同的东西。

Clask在Haskell中没有违反这个定义(试着想出一个:)的闭包,因此闭包不会违反FP范式。