在OCaml中,您无法概括部分应用的curried函数(“值限制”)。
价值限制的目的是什么?如果它不存在会发生什么不愉快?
答案 0 :(得分:18)
如果没有限制泛化的限制或其他机制,类型系统将接受该程序:
let r = (fun x -> ref x) [];; (* this is the line where the value restriction would trigger *)
> r : 'a list ref
r := [ 1 ];;
let cond = (!r = [ "foo" ]);;
变量r
的类型为'a list ref
,这意味着它的内容可以与[ "foo" ]
进行比较,尽管它包含一个整数列表。
请参阅Xavier Leroy's PhD thesis了解更多动机(ref
不是唯一可能想要添加到引入问题的纯lambda演算中的构造)以及对当前存在的系统的调查他的论文(包括他的论文)。
答案 1 :(得分:9)
Here是我前段时间给出的关于F#的答案;问题与OCaml完全相同。问题是如果没有它,我们将能够创建指向错误类型数据的引用:
let f : 'a -> 'a option =
let r = ref None in
fun x ->
let old = !r in
r := Some x;
old
f 3 // r := Some 3; returns None : int option
f "t" // r := Some "t"; returns Some 3 : string option!!!
答案 2 :(得分:2)
weakly polymorphism
here(side-effects-and-weak-polymorphism)有一个很好的描述。
基本上,让我们来看看下面的函数(缓存它看到的第一个值):
# let remember =
let cache = ref None in
(fun x ->
match !cache with
| Some y -> y
| None -> cache := Some x; x)
;;
val remember : '_a -> '_a = <fun>
由于涉及必要,因此应用值限制。
然而,让我们假设没有价值限制。
然后它的类型变为val remember : 'a -> 'a = <fun>
。
如果我现在let () = remember 1
,1
会记录在cache
内,对吗?
如果我第二次呼叫let x = 3 + remember 2
,这应该有效,因为3
是整数,remember
返回与其参数相同的类型。我在这里给2
,所以remember
也返回整数(但是值已经是我们已经记住过的一次)。这应该通过类型检查。
如果我第3次呼叫let y = 3.0 + remember 2.0
怎么办?它会再次起作用吗?
根据记住的类型和我第二次调用背后的原因,它也应该有效,因为我给了remember
浮点数,它应该返回浮点数。
但是因为第一次将1
(整数)存储在内部,它将返回1,这是一个整数。所以类型检查会失败,对吗?
我们可以看到,没有值限制或弱多态,由于允许可变性,整个类型检查会有麻烦。在上面的愚蠢案例中,您需要不断手动检查或跟踪存储的初始类型remember
。