ML中的值限制可防止在可能破坏类型安全的上下文中进行类型泛化。核心问题似乎来自于序列化突变和多态类型的结合,例如在这个OCaml代码中:
let x = ref [];; (* value restriction prevents generalization here *)
x := 1::!x;; (* type unification with int *)
x := true::!x;; (* error *)
没有值限制,最后一行将没有错误地进行类型检查,因为x
的多态类型将与bool
统一。为了防止这种情况,x
的类型必须保持单形。
我的问题如下:是否可以通过使用monads表达操作序列来删除值限制?
作为函数参数,通过monad的bind
操作引入的变量在整个序列中保持单态,因此它似乎在没有在泛化期间引入特殊情况的情况下实现与值限制相同的效果。
这会起作用,如果没有,为什么?
答案 0 :(得分:1)
是的,这基本上有效,而且Haskell是如何做事的。然而,有一个障碍:你必须确保参考永远不会逃脱" monad。伪码:
module MutMonad : sig
(* This is all sound: *)
type 'a t
type 'a ref
val mkref : 'a -> ('a ref) t
val read_ref : 'a ref -> 'a t
val write_ref : 'a -> 'a ref -> unit t
(* This breaks soundness: *)
val run : 'a t -> 'a
end
run的存在让我们回到了我们开始的地方:
let x = run (mkref []) in (* x is of type ('a list) ref *)
run (read_ref x >>= fun list -> write_ref (1::list) x);
run (read_ref x >>= fun list -> write_ref (true::list) x)
Haskell以两种方式解决这个问题:
main
已经是monadic类型(IO),因此它只能没有 runIO或类似内容。对于第二种情况,你有类似的东西:
module MutMonad : sig
(* The types now take an extra type parameter 's,
which is a phantom type. Otherwise, the first
bit is the same: *)
type 'a 's t
type 'a 's ref
val mkref : 'a -> ('a 's ref) 's t
val read_ref : 'a 's ref -> 'a 's t
val write_ref : 'a -> 'a 's ref -> unit 's t
(* This bit is the key. *)
val run : (forall 's. 'a 's t) -> 'a
end
类型级别的forall 's. ...
类似于fun x -> ...
。 &n;是本地绑定变量,因此运行的参数不能假定任何关于它的内容。特别值得一提的是这种类型的检查:
let old_ref = run (mkref 3) in
run (read_ref old_ref)
因为要运行的参数不能假设它们为's
传递相同的类型。
这需要一个在ocaml中不存在的类型系统的特征,并且在Haskell中需要一个langugae扩展(Rank2Types)。