这可能是哲学上的问题,但我相信对此有一个客观的答案。
如果您阅读有关Haskell的维基百科文章,则可以找到以下内容:
该语言源于Haskell Curry及其知识分子后代的观察,即“证明是程序;它证明的公式是程序的类型”。
现在,我要问的是:这真的不适用于几乎所有的编程语言吗?Haskell的哪些功能(或一组功能)使其符合此声明?换句话说,此语句影响语言设计的主要方式是什么?
这可能是哲学上的问题,但我相信对此有一个客观的答案。
如果您阅读有关Haskell的维基百科文章,则可以找到以下内容:
该语言源于Haskell Curry及其知识分子后代的观察,即“证明是程序;它证明的公式是程序的类型”。
现在,我要问的是:这真的不适用于几乎所有的编程语言吗?Haskell的哪些功能(或一组功能)使其符合此声明?换句话说,此语句影响语言设计的主要方式是什么?
Answers:
基本概念以某种方式普遍适用,是的,但很少以有用的方式应用。
首先,从类型理论的角度出发,这假定“动态”语言最好被视为具有单一类型,该类型包含(除其他事项外)有关程序员看到的价值性质的元数据,包括这些动态语言将调用的内容一个“类型”本身(从概念上讲,这是不一样的)。任何此类证明都可能没有意思,因此,该概念与静态类型系统的语言最相关。
另外,在这种情况下,许多据称具有“静态类型系统”的语言在实践中必须被视为动态的,因为它们允许在运行时检查和转换类型。特别是,这意味着任何内置有默认支持“反射”等的语言。例如C#。
Haskell期望类型提供多少信息是不同寻常的-特别是,函数不能依赖除指定为其参数的值以外的任何值。另一方面,在具有可变全局变量的语言中,任何函数都可以(潜在地)检查这些值并相应地更改行为。因此具有类型的Haskell函数A -> B
可以被认为是一个A
隐含的微型程序证明B
; 在许多其他语言中的等效函数只会告诉我们,A
范围内的任何全局状态都暗示B
。
请注意,尽管Haskell确实支持诸如反射和动态类型之类的东西,但必须在函数的类型签名中指示此类功能的使用;同样使用全局状态。默认情况下都不可用。
有有办法通过让运行时异常,或者使用编译器提供的非标准基本操作,打破东西在Haskell为好,如,但那些都具有较强的预期,他们将只能与充分的理解的方式,韩元用于” t破坏外部代码的含义。从理论上讲,其他语言也可以这样说,但是在实践中,大多数其他语言在没有“作弊”的情况下完成任务更加困难,并且对“作弊”的皱眉也更少。当然,在真正的“动态”语言中,整个过程仍然无关紧要。
与在Haskell中相比,该概念可以更进一步。
您是正确的,Curry-Howard对应关系很普遍。值得熟悉一下它的历史:http : //en.wikipedia.org/wiki/Curry-Howard_correspondence
您会注意到,按照最初的表述,这种对应关系一方面特别适用于直觉逻辑,另一方面适用于简单类型的Lambda演算(STLC)。
经典的Haskell-'98或更早的版本,与STLC紧密相关,并且在大多数情况下,Haskell中的任何给定表达式与STLC中的相应术语之间都有非常简单,直接的翻译(扩展了递归和一些原始类型)。因此,这使库里-霍华德非常明确。如今,由于有了扩展,这样的翻译变得有些棘手。
因此,从某种意义上讲,问题是为什么Haskell如此直接地“退出” STLC。我想到两件事:
与大多数语言一样,Haskell在直接应用Curry-Howard对应关系方面也有一种失败的重要方式。Haskell作为一种图灵完备的语言,包含无限递归的可能性,因此也可以终止。STLC没有定点运算符,图灵不完整,并且正在严格规范化 -也就是说,STLC中术语的任何归约都不会终止。递归的可能性意味着人们可以“欺骗” Curry-Howard。例如,let x = x in x
具有类型forall a. a
-即,由于它永远不会返回,我可以假装它给了我任何东西!由于我们始终可以在Haskell中执行此操作,因此这意味着我们无法完全“相信”与Haskell程序相对应的任何证据,除非我们有单独的证据证明程序本身正在终止。
Haskell(特别是ML系列)之前的函数式编程沿袭是CS研究的结果,该研究专注于构建语言,您可以轻松地证明(其中包括)其他事物,这些研究非常了解CH,并且源于CH。相反,Haskell既是宿主语言,又是许多正在开发中的证明助手(例如Agda和Epigram)的灵感,这些助手都植根于与CH世系非常相关的类型理论的发展。
A -> B
给定一个的函数A
将要么产生B
要么什么都不产生。它永远不会产生C
,并且B
它提供的类型值,或者如果不同,仍然完全取决于所A
提供的类型。
Void
,不是吗?懒惰使两者都变得越来越复杂。我想说一个函数A -> B
总是产生type的值B
,但是该值可能包含的信息少于预期的信息。
对于一阶近似,大多数其他(弱类型和/或单类型)语言不支持以下语言之间的严格语言级别划分:
以及两者之间的严格关系。如果有的话,其他此类语言所提供的最佳保证是
请注意,按类型,我们指的是一个命题,因此某些事物描述的信息远比int或bool得多。在Haskell中,函数的渗透文化仅受其参数的影响 - 无例外 *。
稍微严格一点,一般的想法是,通过对(几乎)所有程序结构实施严格的直觉方法(即,我们只能证明我们可以构造的),并通过在这种情况下限制原始结构的集合,我们拥有的方式
Haskell构造倾向于很好地推断其行为。如果我们可以构造一个A
隐含的证明(read:function)证明,B
则它具有非常有用的属性:
A
,我们就可以构造一个B
)A
,而没有其他内容。从而使我们能够有效地推理局部/全局不变量。回到原来的问题;Haskell最能促进这种思维方式的语言功能包括:
所有这些都不是Haskell独有的(其中许多想法都非常古老)。但是,当与标准库中的丰富抽象集(通常在类型类中找到),各种语法级加糖以及对程序设计中的纯净度的严格承诺结合在一起时,我们最终会获得一种在某种程度上能够同时兼顾两者的语言对于现实世界的应用程序足够实用,但同时又证明了比大多数传统语言更容易推理的能力。
这个问题值得一个足够深刻的答案,在这种情况下,我不可能做到公正。我建议阅读更多关于维基百科/文献资料:
* NB:我掩饰/忽略了Haskell杂质的某些棘手方面(异常,非终止等),这些方面只会使论点变得复杂。
该克莱尼层次结构告诉我们,证明不是程序。
第一个递归关系是:
R1( Program , Iteration ) Program halts at Iteration.
R2( Theorem , Proof ) Proof proves a Theorem.
第一个递归可枚举关系是:
(exists x) R1( Program , x ) Program Halts.
(exists x) R2( Theorem , x) Theorem is provable.
因此,程序是一个定理,程序暂停的存在迭代就像证明该定理的存在的证明一样。
Program = Theorem
Iteration = Proof
当从规范正确生成程序时,我们必须能够证明它满足规范,并且如果我们能够证明程序满足规范,那么它就是正确的程序综合。因此,如果我们证明程序满足规范,就可以执行程序综合。程序满足规格的定理是指定理是指所合成的程序的程序。
马丁·洛夫(Martin Lof)的错误结论从未产生过任何计算机程序,令人惊讶的是,人们相信这是一种程序综合方法。尚未给出正在合成的程序的完整示例。诸如“输入类型并输出该类型的程序”之类的规范不是功能。有许多这样的程序,并且随机选择一个程序不是递归函数,甚至不是函数。这只是一个愚蠢的尝试,它显示了一个愚蠢的程序,它并不代表计算递归函数的真实计算机程序。