【发布时间】:2014-01-22 02:06:02
【问题描述】:
我开始学习函数式编程语言,如Haskell、ML,大部分练习都会展示以下内容:
foldr (+) 0 [ 1 ..10]
相当于
sum = 0
for( i in [1..10] )
sum += i
所以这让我想为什么编译器不能知道这是Arithmetic Progression 并使用 O(1) 公式来计算?
特别是对于没有副作用的纯FP 语言?
这同样适用于
sum reverse list == sum list
给定 a + b = b + a 和反向的定义,编译器/语言可以自动证明吗?
【问题讨论】:
-
FP 语言是 lambda 演算的扩展,就像 C 等过程语言是图灵机的扩展一样。在 lambda 演算中,我们有 lambda 项、lambda 抽象和 lambda 应用程序。通过评估 lambda 应用程序,我们只是对它进行了 beta 缩减。类似地,像 Haskell 这样的 FP 语言也使用归约来评估应用程序(Hugs 解释器向您显示归约的数量)。因此,FP 语言基于“lambda 演算的代数”,而不是您在学校学习的代数。这就是为什么 FP 编译器不证明数学定理和优化
-
我相信 Coq 是一种用于证明数学定理的函数式编程语言。然而,它不是图灵完备的。不用说它不是基于 lambda 演算。
-
@AaditMShah 没有澄清,你的说法令人困惑。 lambda-cube 有几个顶点,Haskell 只是其中之一; Coq 和 Agda 是其他一些顶点。另外,不要被图灵完备性所迷惑——拥有图灵完备的语言并不是目标。目标是拥有可以编写有用程序的语言。编写自相矛盾的程序是没有用的(学术除外)。
-
你可以用一些函数式语言证明这些语句,但是你需要比 Haskell 更强大的类型系统(让编译器推断计算法则)。那么a+b=b+a就不再是“Given”了,可以从(+)和Nat的定义中证明。以类似的方式,可以证明原始列表的任何排列都会产生相同的总和。然后可以在需要 a+b 但 b+a 可用的地方使用此事实。
-
这些是非常非常特殊的情况,在实际代码中很少出现。真正的代码倾向于对更复杂的序列进行折叠,其中不存在封闭形式,或者肯定不存在在编译时已知的形式。因此,编译器实现者花时间编写这样的转换是不值得的。
标签: haskell functional-programming ml