不幸的是,有关该主题的许多文献都非常密集。我也是在你的鞋子。我从“编程语言:应用程序和解释”中对该主题进行了首次介绍。
http://www.plai.org/
我将尝试总结抽象的想法,然后总结一些我没有立即发现的细节。首先,可以考虑类型推断来生成约束,然后求解约束。要生成约束,请遍历语法树并在每个节点上生成一个或多个约束。例如,如果节点是+
运算符,则操作数和结果都必须为数字。应用功能的节点的类型与功能的结果相同,依此类推。
对于没有的语言let
,您可以通过替换盲目解决上述限制。例如:
(if (= 1 2)
1
2)
在这里,我们可以说if语句的条件必须为布尔值,并且if语句的类型与其then
和else
子句的类型相同。因为我们知道1
并且2
是数字,所以通过代入,我们知道if
语句是数字。
事情变得令人讨厌,而我一时不了解的地方正在处理let:
(let ((id (lambda (x) x)))
(id id))
在这里,我们绑定id
了一个函数,该函数返回您传入的所有内容,或者称为身份函数。问题在于x
,每次使用时,函数参数的类型都不同id
。第二个id
是type的函数a -> a
,其中a
可以是任何东西。第一个是type (a -> a) -> (a -> a)
。这称为let多态性。关键是按特定顺序解决约束:首先解决的定义的约束id
。这将是a -> a
。然后,id
可以使用的类型的新的独立副本替换每个位置的约束id
,例如a2 -> a2
和a3 -> a3
。
在线资源中并没有很容易解释这一点。他们将提到算法W或M,但没有提到它们在解决约束方面的工作方式,或者为什么它不会阻碍let多态性:每种算法都在解决约束时强制执行排序。
我发现该资源对于将算法W,M以及约束生成和求解的一般概念结合在一起非常有帮助。它有点密集,但比许多要好:
http://www.cs.uu.nl/research/techreps/repo/CS-2002/2002-031.pdf
那里的许多其他论文也很好:
http://people.cs.uu.nl/bastiaan/papers.html
我希望这有助于澄清一个有点模糊的世界。