Functional programming Hindley-Milner型系统中letrec的正确形式?
我很难理解维基百科上给出的HM系统的letrec定义,这里: 对我来说,这条规则大致可以转化为以下算法:Functional programming Hindley-Milner型系统中letrec的正确形式?,functional-programming,type-inference,lambda-calculus,hindley-milner,Functional Programming,Type Inference,Lambda Calculus,Hindley Milner,我很难理解维基百科上给出的HM系统的letrec定义,这里: 对我来说,这条规则大致可以转化为以下算法: 推断letrec定义部分中所有内容的类型 为每个定义的标识符分配临时类型变量 使用临时类型递归处理所有定义 成对使用原始临时变量统一结果 关闭(对于所有)推断的类型,将它们添加到基础(上下文)中,并使用它推断表达式部分的类型 我在这样的程序中遇到了问题: letrec p = (+) --has type Uint -> Uint -> Uint x = (letr
letrec
定义部分中所有内容的类型
letrec
p = (+) --has type Uint -> Uint -> Uint
x = (letrec
test = p 5 5
in test)
in x
我观察到的行为如下:
的定义获取临时类型p
a
的定义也得到了一些临时类型,但这不在我们的范围之内x
- 在
中,x
的定义获取一个临时类型test
t
使用变量的HM规则从范围中获取临时类型p
a
由HM规则处理以供应用,结果类型为(f 5)
(以及(b
与a
相统一)Uint->b
通过相同的规则进行处理,导致更多的统一和类型((p 5)5)
,c
现在的结果与a
Uint->Uint->c
- 现在,对于所有c.c
- test中
),从而生成的变量test根据变量的HM规则,获取具有新变量的类型实例(或所有c.c
(与test::d
统一)test::t
- 产生的
具有有效的x
(或d
,取决于统一的情绪)t
x
显然应该有类型Uint
,但我认为这两个类型不可能统一生成该类型。当test
的类型关闭并再次实例化时,会丢失信息,我不确定如何克服或连接替换/统一
你知道该如何修正算法以正确键入x::Uint
吗?或者这是HM系统的一个属性,它根本不会键入这种情况(我对此表示怀疑)
请注意,对于标准的let
,这完全可以,但我不想用let
无法处理的递归定义混淆示例
提前感谢您回答我自己的问题: Wiki上的定义是错误的,尽管它至少在某种程度上适用于类型检查 将递归添加到HM系统中最简单、最正确的方法是使用
fix
谓词,定义为fix f=f(fix f)
并键入forall a.(a->a)->a
。相互递归由双不动点处理,等等
Haskell解决问题的方法(在中描述)是(大致)为所有函数派生一个不完整的类型,然后再次运行派生以相互检查。wiki上的定义在我看来确实是正确的。你能指出错误的地方吗?