我正在开发一个小型lambda演算编译器,该编译器具有运行正常的Hindley-Milner类型推断系统,并且现在还支持递归let(不在链接代码中),据我所知应该足以使Turing完成。
现在的问题是我不知道如何使它成为支持列表,或者它是否已经支持它们,我只需要找到一种编码它们的方法。我希望能够定义它们,而不必向类型系统中添加新规则。
我想到的一个列表的最简单方法x
是将其作为null
(或为空列表),或同时包含x
和的列表对x
。但是要做到这一点,我需要能够定义对和或,我相信它们是乘积和总和类型。
看来我可以这样定义对:
pair = λabf.fab
first = λp.p(λab.a)
second = λp.p(λab.b)
因为pair
将具有类型a -> (b -> ((a -> (b -> x)) -> x))
,所以在传递一个int
和一个后string
,它会产生一个带有类型的东西(int -> (string -> x)) -> x
,这将是一对int
and 的表示string
。这里令我困扰的是,如果那个代表一对,那为什么在逻辑上不等同于或暗示这个命题int and string
呢?但是,等效于(((int and string) -> x) -> x)
,好像我只能将产品类型作为函数的参数一样。这个答案似乎解决了这个问题,但我不知道他使用的符号是什么意思。另外,如果这不能真正对产品类型进行编码,那么我对上面的对的定义无法做到的产品类型(考虑到我也可以用相同的方式定义n元组)做任何事情?如果不是,这是否与仅使用蕴涵就不能表达(AFAIK)连词的事实相矛盾?
另外,总和类型呢?我可以仅使用函数类型以某种方式对其进行编码吗?如果是这样,是否足以定义列表?否则,是否有其他方法可以定义列表而不必扩展我的类型系统?如果不是这样,如果我想使其尽可能简单,我需要进行哪些更改?
请记住,我是计算机程序员,但不是计算机科学家或数学家,并且在阅读数学符号方面相当不擅长。
编辑: 我不确定到目前为止实现的技术名称是什么,但是我所拥有的基本上只是上面链接的代码,这是一种约束生成算法,使用应用程序规则,抽象规则和变量先从Hinley-Milner算法开始,然后是获得主体类型的统一算法。例如,该表达式\a.a
将产生type a -> a
,并且该表达式\a.(a a)
将引发一个发生检查错误。最重要的是,这里没有一个确切的let
规则,但是一个函数似乎具有与您定义递归全局函数(如此伪代码)相同的作用:
GetTypeOfGlobalFunction(term, globalScope, nameOfFunction)
{
// Here 'globalScope' contains a list of name-value pair where every value is of class 'ClosedType',
// meaning their type will be cloned before unified in the unification algorithm so that they can be used polymorphically
tempType = new TypeVariable() // Assign a dummy type to `tempType`, say, type 'x'.
// The next line creates an scope with everything in 'globalScope' plus the 'nameOfFunction = tempType' name-value pair
tempScope = new Scope(globalScope, nameOfFunction, tempType)
type = TypeOfTerm(term, tempScope) // Calculate the type of the term
Unify(tempType, type)
return type
// After returning, the code outside will create a 'ClosedType' using the returned type and add it to the global scope.
}
代码基本上像往常一样获得术语的类型,但是在统一之前,它会将用伪类型定义的函数的名称添加到类型范围中,以便可以在其内部递归使用。
编辑2:我刚刚意识到,我还需要递归类型来定义所需的列表,而我没有。
let func = \x -> (func x)
)可以得到我所拥有的。