OCaml 中的弱多态性
Posted
技术标签:
【中文标题】OCaml 中的弱多态性【英文标题】:Weak Polymorphism in OCaml 【发布时间】:2013-07-28 16:13:11 【问题描述】:我对 OCaml 中的弱多态性有点困惑。
请看下面的sn-p,这里我定义了一个函数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
成为本地使用的。为什么会这样?
【问题讨论】:
【参考方案1】: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
只能存储一种类型。
在下一个中,你关闭了两个东西,x
和 cache
。由于我们在每次调用remember
时创建了一个新的cache
ref,因此该类型可以再次完全多态。该类型不是弱多态的原因是因为我们知道我们将在其中存储x
,并且在创建cache
时我们有x
s 类型。
【讨论】:
我猜你的意思是cache
的类型为int option ref
而不是ref (None int)
。【参考方案2】:
这似乎与价值限制有关。全值限制(如在 SML 中)将完全拒绝您的代码。 Jacques Garrigue 的论文“Relaxing the Value Restriction”中描述了弱多态类型,我承认我是在阅读您的问题后偶然发现的:
http://caml.inria.fr/pub/papers/garrigue-value_restriction-fiwflp04.pdf
如果您对 ML 代码的含义有一个正确的思维模型,那么 cache
在调用之间共享这一事实应该是显而易见的。您正在定义两个值,remember
和 cache
。嵌套只是使 cache
的范围对块私有。
【讨论】:
【参考方案3】: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
调用之间共享。
【讨论】:
你的“其他版本”解决了昨天下午大部分时间让我思考的代码!以上是关于OCaml 中的弱多态性的主要内容,如果未能解决你的问题,请参考以下文章