“What part of Hindley-Milner do you not understand?”
我发誓曾经有一件T恤出售,上面写着不朽的话:
什么部分
难道你不明白?
就我而言,答案就是......全部!
特别是,我经常在Haskell论文中看到这样的符号,但我不知道它的含义是什么。 我不知道它应该是什么样的数学分支。
我当然认识到希腊字母的字母,以及诸如"?"之类的符号。 (这通常意味着某些东西不是一组的元素)。
另一方面,我从未见过"?" 之前(维基百科称它可能意味着"分区")。 我也不熟悉这里使用的vinculum。 (通常它表示一个分数,但这似乎不是这种情况。)
如果有人至少可以告诉我从哪里开始想要理解这个符号海洋的含义,那将会有所帮助。
- 水平条表示"[以上]暗示[下方]"。
- 如果[上面]中有多个表达式,那么将它们一起考虑;所有[上述]必须为真以保证[下方]。
-
: 表示有类型 -
∈ 表示在。(同样? 表示"不在"中。) -
Γ 通常用于指代环境或上下文;在这种情况下,它可以被认为是一组类型注释,将标识符与其类型配对。因此,x : σ ∈ Γ 表示环境Γ 包括x 具有类型σ 的事实。 -
? 可以作为证明或确定来阅读。Γ ? x : σ 表示环境Γ 确定x 的类型为σ 。 -
, 是一种将特定的附加假设包含在环境Γ 中的方法。
因此,Γ, x : τ ? e : τ' 表示环境Γ ,其中x 具有类型τ 的附加的重写假设证明e 具有类型τ' 。
根据要求:运营商优先级,从最高到最低:
-
特定于语言的中缀和mixfix运算符,例如
λ x . e ,? α . σ 和τ → τ' ,let x = e0 in e1 以及用于函数应用的空白。 -
: -
∈ 和? -
, (左联想) -
? - 分隔多个命题的空格(关联)
- 横杠
这种语法虽然看起来很复杂,但实际上相当简单。基本思想来自形式逻辑:整个表达是一种含义,上半部分是假设,下半部分是结果。也就是说,如果你知道顶部表达式是真的,你可以得出结论底部表达式也是真的。
符号
另外要记住的是,有些字母具有传统意义;特别是,Γ代表你所处的"背景" - 即你所看到的其他类型的东西。所以当你知道
另外要记住的是:在数学中,就像ML和Scala一样,
每条规则的含义
所以,知道这一点,第一个表达式变得易于理解:如果我们知道
其他规则也很简单。例如,取
下一个规则有一些新的语法。特别地,
下一个只是告诉你如何处理
最终规则涉及泛化类型。快速搁置:自由变量是一个变量,它不是由某个表达式中的let语句或lambda引入的;这个表达式现在依赖于来自其上下文的自由变量的值。规则是说如果在你的上下文中有任何变量
如何使用规则
那么,既然您已了解符号,那么您对这些规则有何看法?好吧,您可以使用这些规则来确定各种值的类型。要执行此操作,请查看您的表达式(例如
因此,所有这些规则都是精确地指定 - 并且在通常的数学上迂腐的细节:P-如何找出表达式的类型。
现在,如果您曾经使用Prolog,这应该听起来很熟悉 - 您实际上是像人类Prolog解释器一样计算证明树。 Prolog被称为"逻辑编程"是有原因的!这也很重要,因为我介绍H-M推理算法的第一种方法是在Prolog中实现它。这实际上非常简单,并且清楚地表明了这一点。你当然应该尝试一下。
注意:我可能在这个解释中犯了一些错误,并且如果有人指出它们会很喜欢它。我实际上会在几周内在课堂上报道,所以我会更自信:P。
好。
if somebody could at least tell me where to start looking to comprehend what this sea of symbols means
参见"编程语言的实用基础",第2章和第3章,通过判断和推导来讨论逻辑风格。整本书现已在亚马逊上市。
第2章
归纳定义
归纳定义是编程语言研究中不可或缺的工具。在本章中,我们将开发归纳定义的基本框架,并举例说明它们的使用。归纳定义包括一组用于推导各种形式的判断或断言的规则。判断是关于指定排序的一个或多个句法对象的陈述。规则规定了判决有效性的必要和充分条件,从而充分确定其含义。
2.1判决
我们从判断的概念开始,或者关于句法对象的断言。我们将利用多种形式的判断,包括以下例子:
- n nat - n是一个自然数
- n = n1 + n2 -n是n1和n2之和
- τtype - τ是一种类型
- e:τ - 表达式e具有类型τ
- e? v - 表达式e具有值v
判断表明一个或多个句法对象具有彼此某种关系的属性或立场。财产或关系本身被称为判断形式,并且一个或多个对象在该关系中具有该属性或立场的判断被认为是该判断形式的实例。判断形式也称为谓词,构成实例的对象是其主语。我们为判断断言J持有a而写了一个J.当强调判断的主题并不重要时,(文字在这里切断)
符号来自自然演绎。
?符号被称为旋转栅门。
这6条规则非常简单。
我如何理解Hindley-Milner规则?
Hindley-Milner是一组以后续演算(非自然演绎)形式出现的规则,它表明我们可以在没有明确类型声明的情况下从程序的构造中推导出(最常规)类型的程序。
符号和符号
首先,让我们解释符号,并讨论运算符优先级
????。??意思是? (lambda)是一个匿名函数,它接受一个参数,??,并返回一个表达式,??。
让?? = ???在???在表达中表示,???,替换???哪里?出现。
?表示先前元素是后一元素的子类型(非正式 - 子类)。
线上的一切都是前提,下面的一切都是结论(Per Martin-L?f)
优先,例如
我从规则中选取了一些更复杂的例子,并插入了显示优先级的冗余括号:
?? ? ?? :??可以写? ? (??:??)
?? ?让?? = ???在??? :??
是等价的
?? ? ((让(?? = ???)in ???):??)
?? ? ????。?? :??→??'是等价的? ? ((????。??):( ??→??'))
然后,分隔断言语句和其他前提条件的大空间表示一组这样的前提条件,最后将前提与结论分开的水平线引出优先顺序的结束。
规则
接下来是对规则的英语解释,每个解释都是松散的重述和解释。
变量
Given ?? is a type of ?? (sigma), an element of ?? (Gamma),
conclude ?? asserts ?? is a ??.Ok.
换句话说,在??,我们知道??是类型??因为??是类型??在?? ??
这基本上是一个重言式。标识符名称是变量或函数。
功能应用
Given ?? asserts ??? is a functional type and ?? asserts ??? is a ??
conclude ?? asserts applying function ??? to ??? is a type ??'Ok.
要重述规则,我们知道函数应用程序返回类型??'因为函数有类型??→??'并获得类型??的参数。
这意味着如果我们知道一个函数返回一个类型,并将它应用于一个参数,那么结果将是我们知道它返回的类型的实例。
功能抽象
Given ?? and ?? of type ?? asserts ?? is a type, ??'
conclude ?? asserts an anonymous function, ?? of ?? returning expression, ?? is of type ??→??'.Ok.
再次,当我们看到一个需要的功能??并返回一个表达式??,我们知道它的类型?? ?? ?? ??因为?? (a ??)断言??是一个??'。
如果我们知道??是类型??因而表达?是'??'的类型,然后是??的函数?回归表达?是?? ?? ?? ??的类型。
让变量声明
Given ?? asserts ???, of type ??, and ?? and ??, of type ??, asserts ??? of type ??
conclude ?? assertslet ??=???in ??? of type ??Ok.
松散地,??一定会 ???在??? (a ??)因为???是一个??,??是??断言???是一个?
这意味着如果我们有一个表达式???这是一个 ?? (是变量或函数),有些名称,??,也是??,和表达式???类型??,那么我们可以替代???为?? ??哪里出现???。
实例化
Given ?? asserts ?? of type ??' and ??' is a subtype of ??
conclude ?? asserts ?? is of type ??Ok.
一种表达, ??是父类型??因为表达??是子类型??'和??是''的父类型。
如果实例的类型是另一种类型的子类型,那么它也是该超类型的实例 - 更通用的类型。
概括
Given ?? asserts ?? is a ?? and ?? is not an element of the free variables of ??,
conclude ?? asserts ??, type for all argument expressions ?? returning a ?? expressionOk.
所以总的来说,??键入?对于所有参数变量(??)返回??,因为我们知道??是??和??不是一个自由变量。
这意味着我们可以将程序概括为接受所有类型的参数,这些参数尚未绑定在包含范围内(非非本地变量)。这些绑定变量是可替代的。
把它们放在一起
给定某些假设(例如没有自由/未定义的变量,已知环境),我们知道以下类型:
结论
这些规则的组合使我们能够证明断言程序的最一般类型,而无需类型注释。
好。
有两种方法可以考虑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具有类型αασ。