我无法理解维基百科上给出的 HM 系统的 letrec 定义,这里:https ://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system#Recursive_definitions
对我来说,该规则大致转换为以下算法:
- 推断
letrec
定义部分 中所有内容的类型- 将临时类型变量分配给每个定义的标识符
- 递归处理所有具有临时类型的定义
- 成对,将结果与原始临时变量统一起来
- 关闭(用
forall
)推断的类型,将它们添加到基础(上下文)并用它推断表达式部分的类型
我在使用这样的程序时遇到问题:
letrec
p = (+) --has type Uint -> Uint -> Uint
x = (letrec
test = p 5 5
in test)
in x
我观察到的行为如下:
p
获取临时类型的定义a
- 的定义也
x
有一些临时类型,但这已经超出了我们的范围 - in
x
, 的定义test
得到一个临时类型t
p
从作用域中获取临时类型a
,对变量使用 HM 规则(f 5)
由应用程序的 HM 规则处理,结果类型是b
(以及(a
统一与)的统一Uint -> b
)((p 5) 5)
由相同的规则处理,产生更多的统一和类型c
,a
现在结果统一为Uint -> Uint -> c
- 现在,测试关闭输入
forall c.c
- 变量测试
in test
获取类型实例(或forall c.c
)带有新鲜变量,根据变量的HM规则,导致test :: d
(即与test::t
右上统一) - 结果
x
具有有效的类型d
(或t
,取决于统一的心情)
问题:x
显然应该有 type Uint
,但我认为这两者不可能统一产生类型。当类型test
被关闭并再次实例化时会丢失信息,我不确定如何克服或连接替换/统一。
知道如何更正算法以x::Uint
正确生成打字吗?或者这是 HM 系统的一个属性,它根本不会输入这种情况(我怀疑)?
请注意,这对于 standard 来说是完全可以的let
,但我不想用无法处理的递归定义来混淆示例let
。
提前致谢