我对OCaml中的弱多态性有点困惑。
请参阅以下代码片段,其中我定义了一个函数remember
:
let remember x =
let cache = ref None in
match !cache with
| Some y -> y
| None -> cache := Some x; x
;;
编译器可以推断出多态类型'a -> 'a
,cache
在本地使用。
但是当我将上面的代码修改成
let remember =
let cache = ref None in
(fun x -> match !cache with
| Some y -> y
| None -> cache := Some x; x)
;;
编译器推断出弱多态类型'_a -> '_a
,而且,似乎cache
在remember
的调用之间共享。
编译器在这里推断弱多态类型,为什么共享cache
?
更重要的是,如果我再次更改代码
let remember x =
let cache = ref None in
(fun z -> match !cache with
| Some y -> z
| None -> cache := Some x; x)
;;
编译器推断多态类型'a -> 'a -> 'a
,cache
在本地使用。为什么会这样呢?
let remember =
let cache = ref None in
(fun x -> match !cache with
| Some y -> y
| None -> cache := Some x; x)
;;
在这里,cache
被返回的函数关闭。但是在我们声明cache
的时候,我们没有关于类型的信息;它将由x
的类型决定,并在定义remember
时创建cache
。
但是由于这是一个闭包,我们可以做这样的事情:
> remember 1
1
现在很明显,cache : int option ref
因为我们实际上在其中存储了一些东西。因为只有一个cache
,remember
只能存储一种类型。
在下一个中,您将关闭 2 件事,x
和cache
。由于我们在每次调用remember
时都会创建一个新的 cache
ref,因此该类型可以再次完全多态。该类型不是弱多态的原因是,我们知道我们要在其中存储x
,并且在创建cache
时x
类型。
这似乎与值限制有关。全值限制(如在 SML 中(将完全拒绝您的代码。弱多态类型在雅克·加里格(Jacques Garrigue(的论文"放宽价值限制"中进行了描述,我承认在阅读了您的问题后偶然发现了它:
http://caml.inria.fr/pub/papers/garrigue-value_restriction-fiwflp04.pdf
如果你对 ML 代码的含义有一个正确的心智模型,那么cache
在调用之间共享的事实应该是显而易见的。 您正在定义两个值,remember
和 cache
。嵌套只是使cache
的范围私有于块。
let remember x =
let cache = ref None in
match !cache with
| Some y -> y
| None -> cache := Some x; x
let remember x =
let cache = ref None in
(fun z -> match !cache with
| Some y -> z
| None -> cache := Some x; x)
在上面的两个版本中,remember
是一个"直接"函数,每次像remember 1
一样调用它,它都会初始化cache
ref None
,不是吗?所以实际上,它什么都不记得,cache
不会在任何remember
调用之间共享。
在另一个版本中:
let remember =
let cache = ref None in
(fun x -> match !cache with
| Some y -> y
| None -> cache := Some x; x)
这是不同的。 remember
肯定仍然是一个功能,但是,定义其内容的真正部分是 (fun x -> match ...)
.它包括cache
,缓存初始化一次,并且只会初始化一次。因此,cache
在未来remember
电话之间共享。