纯函数式语言真的能保证不变性吗?

Dax*_*ohl 3 functional-programming immutability purely-functional

在纯函数式语言中,不能仍然定义一个"赋值"运算符,比如"< - ",这样命令,比如"i < - 3",而不是直接分配不可变变量i,就会创建整个当前调用堆栈的副本,​​除了在新调用堆栈中用3替换i,并从该点开始执行新的调用堆栈?鉴于实际上没有数据发生变化,根据定义,这仍然不会被视为"纯功能"吗?当然编译器只是简单地将优化分配给i,在这种情况下,命令式和纯函数之间的区别是什么?

Dan*_*ker 5

纯函数式语言(如Haskell)具有对命令式语言进行建模的方法,并且他们也不会羞于承认它.:)

http://www.haskell.org/tutorial/io.html,特别是7.5:

那么,最终,Haskell只是重新发明了势在必行的轮子?

从某种意义上说,是的.I/O monad在Haskell中构成了一个小的命令式子语言,因此程序的I/O组件可能看起来类似于普通的命令式代码.但是有一个重要的区别:用户不需要处理特殊的语义.特别是,Haskell中的等式推理不会受到损害.程序中monadic代码的强制性感觉并没有减损Haskell的功能方面.经验丰富的函数式程序员应该能够最小化程序的必要组件,只使用I/O monad进行最少量的顶级排序.monad干净地分离了功能和命令式程序组件.相比之下,具有功能子集的命令式语言通常在纯粹的功能性和命令性世界之间没有任何明确的障碍.

因此,函数式语言的价值并不在于它们使状态变异变得不可能,而是它们提供了一种方法,允许您将程序的纯函数部分与状态变异部分分开.

当然,您可以忽略这一点并以命令式方式编写整个程序,但是您不会利用该语言的设施,那么为什么要使用它呢?

更新

你的想法没有你想象的那样有缺陷.首先,如果只熟悉命令式语言的人想要遍历一系列整数,他们可能想知道如何在没有增加计数器的方法的情况下实现这一点.

但是当然你只需要编写一个充当循环体的函数,然后让它自己调用.函数的每次调用对应于"迭代步骤".并且在每次调用的范围内,参数具有不同的值,就像递增变量一样.最后,运行时可以注意到递归调用出现在调用的最后,因此它可以重用函数调用堆栈的顶部而不是增长它(尾调用).即使这个简单的模式几乎具有你想法的所有风格 - 包括编译器/运行时悄悄地插入并实际发生突变(覆盖堆栈的顶部).它不仅在逻辑上等同于具有变异计数器的循环,而且实际上它使CPU和内存在物理上做同样的事情.

你提到一个GetStack会将当前堆栈作为数据结构返回.这确实会违反功能纯度,因为每次调用时它都必须返回不同的东西(没有参数).但是如果一个函数CallWithStack传递给你自己的函数,它会回调你的函数并将当前堆栈作为参数传递给它?那将是完全可以的.CallCC的工作方式有点像.

  • @Dax:这似乎是真实的我,但如果你看看Haskell的类型[`callCC`](http://hackage.haskell.org/packages/archive/mtl/latest/doc/html/Control-Monad- Cont-Class.html #v:callCC),它是`MonadCont m =>((a - > mb) - > ma) - > ma`.continuation monad捕获continuation的语义,因此允许你以这种方式工作(只要你留在它里面). (2认同)