如果您正在寻找对类型推断的整洁,功能性的参考,那么我会偏爱Gundry,McBride和McKinna的2010年“ 上下文中的类型推断 ”,尽管这可能并不适合任何实际的现有实现。
我认为答案的一部分是,除了价值限制之外,将Hindley-Milner类型推断适应命令式语言的确没有太大困难:如果您将定义e1; e2
为语法糖,(fn _ => e2) e1
并且将定义while e1 do e2
为语法糖whiledo e1 (fn () => e2)
,whiledo
那么递归函数
fun whiledo g f = if g then (f (); whiledo g f) else ();
那么一切都将正常工作,包括类型推断。
至于价值限制是一种特殊的技巧,我喜欢以下故事。我敢肯定,我是从卡尔·克拉里(Karl Crary)那里捡来的。考虑以下代码,其值限制将阻止您编写ML:
let
val x: 'a option ref = ref NONE
in
(x := SOME 5; x := SOME "Hello")
end
将其与以下代码进行比较,这完全没有问题:
let
val x: unit -> 'a option ref = fn () => ref NONE
in
(x () := SOME 5; x () := SOME "Hello")
end
我们知道第二个示例的作用:它创建两个新的ref单元格,其中包含NONE
,然后放入SOME 5
第一个(an int option ref
),然后放入SOME "Hello"
第二个(a string option ref
)。
x
x
∀ α 。ref(选项(α ))x
Λ α 。参考 [ α ] (无)
这表明第一个示例的一个“良好”行为是与第二个示例的行为完全相同-在不同的时间实例化类型级lambda。第一次实例化x
时int
,它将导致x [int]
求值到保存的参考单元格NONE
,然后SOME 5
。第二次使用实例化x
时string
,将得出x [string]
求(一个不同的)参考单元格的值NONE
,然后按SOME "Hello"
。这种行为是“正确的”(类型安全的),但是绝对不是程序员所期望的,这就是为什么我们在ML中设置值限制,以避免程序员处理这种意外行为。
let val x = ref 9 in while !x>0 do (print (Int.toString (!x)); x := !x-1) end
。因此,在研究问题的层面上,您正在寻找的答案是“应用在Caml / SML中开发的技术,包括价值限制”吗?