“你不明白欣德利 - 米尔纳的哪一部分?”

时间:2012-09-21 14:29:45

标签: haskell functional-programming lambda-calculus hindley-milner denotational-semantics

发誓曾经有一件T恤出售,其中包含不朽的词语:


的哪一部分

Hindley-Milner

明白吗?


就我而言,答案就是......全部!

特别是,我经常在Haskell论文中看到这样的符号,但我不知道它的含义是什么。我不知道它应该是什么样的数学分支。

我当然认识到希腊字母的字母,以及诸如“∉”之类的符号(通常意味着某些东西不是一组元素)。

另一方面,我以前从未见过“⊢”(Wikipedia claims it might mean "partition")。我也不熟悉这里使用的vinculum。 (通常它表示一个分数,但这里不会出现 。)

如果有人至少可以告诉我从哪里开始想要了解这个符号海洋的含义,那将会有所帮助。

5 个答案:

答案 0 :(得分:615)

  • 水平条表示“[上方] 暗示 [下方]”。
  • 如果[上面]中有多个表达式,那么一起考虑 anded ;所有[上述]必须为真,以保证[以下]。
  • :表示有类型
  • 表示位于。 (同样表示“不在”。)
  • Γ通常用于指代环境或上下文;在这种情况下,它可以被认为是一组类型注释,将标识符与其类型配对。因此,x : σ ∈ Γ表示环境Γ包含x类型为σ的事实。
  • 可以读作证明或确定。 Γ ⊢ x : σ表示环境Γ确定x的类型为σ
  • ,是一种包含特定附加假设的方式Γ
    因此,Γ, x : τ ⊢ e : τ'表示环境Γ带有x类型为τ 的额外重写假设,证明e类型为τ'

根据要求:运营商优先级,从最高到最低:

  • 特定于语言的中缀和mixfix运算符,例如λ x . e∀ α . στ → τ'let x = e0 in e1以及用于函数应用的空格。
  • :
  • ,(左联想)
  • 分隔多个命题的空格(关联)
  • 横条

答案 1 :(得分:317)

这种语法虽然看起来很复杂,但实际上相当简单。基本思想来自形式逻辑:整个表达是一种含义,上半部分是假设,下半部分是结果。也就是说,如果您知道顶部表达式为真,则可以得出结论:底部表达式也是正确的。

符号

要记住的另一件事是,有些字母具有传统意义;特别是,Γ代表你所处的“背景” - 即你所看到的其他类型的东西。因此,当您知道Γ ⊢ ...中每个表达式的类型时,...之类的含义就意味着“Γ

符号实质上意味着您可以证明某些事物。所以Γ ⊢ ...是一句话,说“我可以在上下文...中证明Γ。这些陈述也称为类型判断。

要记住的另一件事:在数学中,就像ML和Scala一样,x : σ表示x具有类型σ。您可以像Haskell的x :: σ一样阅读它。

每条规则的含义

因此,知道这一点,第一个表达式变得易于理解:如果我们知道x : σ ∈ Γ(即x在某些上下文σ中有某种类型Γ ),然后我们知道Γ ⊢ x : σ(即Γx的类型为σ)。所以真的,这并没有告诉你任何超级有趣的东西;它只是告诉你如何使用你的上下文。

其他规则也很简单。例如,取[App]。此规则有两个条件:e₀是某种类型τ到某种类型τ'的函数,e₁是类型τ的值。现在,您可以通过将e₀应用于e₁来了解您将获得的类型!希望这不是一个惊喜:)。

下一条规则有一些新的语法。特别是,Γ, x : τ仅表示由Γ和判断x : τ组成的上下文。因此,如果我们知道变量x的类型为τ且表达式e的类型为τ',那么我们也知道x的函数类型{ {1}}并返回e。这只是告诉我们如果我们弄清楚函数采用什么类型以及返回什么类型该怎么做,所以它也不应该令人惊讶。

下一个只是告诉你如何处理let语句。如果您知道某个表达式e₁的类型为τ,只要x的类型为σ,那么let表达式会在x本地绑定σ如果e₁类型的值将使τ具有类型let。实际上,这只是告诉你一个let语句基本上允许你用一个新的绑定扩展上下文 - 这正是[Inst]所做的!

σ'规则处理子类型。它说如果你有σ类型的值并且它是的子类型(σ表示部分排序关系)那么表达式也是类型α

最终规则涉及概括类型。快速搁置:自由变量是一个变量,它不是由某个表达式中的let语句或lambda引入的;这个表达式现在取决于其上下文中的自由变量的值。规则是说如果在你的上下文中有任何变量e : σ “free”,那么可以肯定地说,您知道α类型的任何表达式都具有任何f x y的类型。

如何使用规则

所以,既然您已了解符号,那么您对这些规则有何看法?好吧,您可以使用这些规则来确定各种值的类型。要执行此操作,请查看您的表达式(例如e₀ e₁)并查找与您的语句匹配的结论(底部)的规则。让我们称之为你想要找到你的“目标”。在这种情况下,您将查看以{{1}}结尾的规则。当你发现这一点时,你现在必须找到规则,证明这条规则的所有内容。这些东西通常对应于子表达式的类型,因此您实际上是对表达式的某些部分进行递归。您只需执行此操作,直到完成校对树,这样可以证明表达式的类型。

因此,所有这些规则都是精确地指定 - 并且在通常的数学上迂腐的细节:P-如何找出表达式的类型。

现在,如果您曾经使用Prolog,这应该听起来很熟悉 - 您实际上是像人类Prolog解释器一样计算证明树。 Prolog被称为“逻辑编程”是有原因的!这也很重要,因为我介绍H-M推理算法的第一种方法是在Prolog中实现它。这实际上非常简单,并且清楚地表明了这一点。你当然应该尝试一下。

注意:我可能在这个解释中犯了一些错误,如果有人指出它们,我会很喜欢它。我实际上会在几周内在课堂上报道,所以我会更自信:P。

答案 2 :(得分:70)

  

如果有人至少可以告诉我从哪里开始想要了解这个符号海洋意味着什么

参见“Practical Foundations of Programming Languages.”,第2章和第3章,通过判断和推导得出逻辑风格。整本书都是now available on Amazon.

第2章

归纳定义

归纳定义是编程语言研究中不可或缺的工具。在本章中,我们将开发归纳定义的基本框架,并举例说明它们的使用。归纳定义由一组规则组成,用于派生各种形式的判断断言。判断是关于指定排序的一个或多个句法对象的陈述。规则为判断的有效性规定了必要和充分的条件,从而完全确定其含义。

2.1判决

我们从关于句法对象的判断断言的概念开始。我们将利用多种形式的判断,包括这些例子:

  • n nat - n 是自然数
  • n = n1 + n2 - n n1 的总和和 n2
  • τ 类型 - τ是一种类型
  • e τ - 表达式 e 的类型为τ
  • e v - 表达式 e 的值为 v

判断表明一个或多个句法对象具有彼此某种关系的属性或立场。属性或关系本身被称为判断形式,并且一个或多个对象具有该属性或站在该关系中的判断被认为是该判断的实例形成。判断表单也称为谓词,构成实例的对象是 subject 。我们写 a J 作判断断言 J 持有 a 。当强调判断的主题并不重要时(文字在这里切断)

答案 3 :(得分:48)

符号来自natural deduction

⊢符号称为turnstile

这6条规则非常简单。

Var规则是相当简单的规则 - 它表示如果类型环境中已存在标识符的类型,那么要推断出您只是从环境中获取它的类型。

App规则说,如果您有两个标识符e0e1并且可以推断其类型,那么您可以推断应用程序的类型e0 e1。如果您知道e0 :: t0 -> t1e1 :: t0(相同的t0!),则规则会如下所示,然后应用程序输入良好且类型为t1

AbsLet是推断lambda抽象和let-in类型的规则。

Inst规则说您可以用较不普遍的类型替换类型。

答案 4 :(得分:16)

有两种方法可以考虑e:σ。一个是“表达式e具有类型σ”,另一个是“表达式e和类型σ的有序对”。

查看Γ作为表达式类型的知识,实现为一组表达式和类型,e:σ。

旋转门⊢意味着从左边的知识中我们可以推断出右边的内容。

因此可以读取第一条规则[Var]:
如果我们的知识Γ包含对e:σ,那么我们可以从Γ推导出e具有类型σ。

可以阅读第二条规则[App]:
如果我们从Γ可以推断出e_0具有类型τ→τ',并且我们从Γ可以推断出e_1具有类型τ,那么我们从Γ可以推断出e_0 e_1具有类型τ'。

通常写Γ,e:σ而不是Γ∪{e:σ}。

因此可以读出第三条规则[Abs]:
如果我们从Γ扩展到x:τ可以推导出e具有类型τ',那么我们从Γ可以推导出λx.e具有类型τ→τ'。

第四条规则[让]留作练习。 : - )

第五条规则[Inst]可以理解为:
如果我们从Γ可以推导出e具有类型σ',并且σ'是σ的子类型,那么我们从Γ可以推导出e具有类型σ。

可以阅读第六个也是最后一个规则[Gen]:
如果我们从Γ可以推导出e具有类型σ,并且α在Γ中的任何类型中都不是自由类型变量,那么我们从Γ可以推导出e具有类型∀ασ。