使用ref单元进行动态绑定

尼克·扎鲁茨基(Nick Zalutskiy)

我了解您无法执行此操作,但想确切了解原因。

module M : sig 
  type 'a t
  val call : 'a t -> 'a option
end = struct 
  type 'a t
  let state : ('a t -> 'a option) ref = ref (fun _ -> None)
  let call : ('a t -> 'a option) = fun x -> !state x
end

结果是:

Error: Signature mismatch:
Modules do not match:
    sig 
        type 'a t
        val state : ('_a t -> '_a option) ref
        val call : '_a t -> '_a option
    end
is not included in
    sig 
        type 'a t 
        val call : 'a t -> 'a option 
    end

    Values do not match:
        val call : '_a t -> '_a option
    is not included in
        val call : 'a t -> 'a option

为什么抽象类型在这里不兼容?

我的直觉告诉我,它与早期绑定和后期绑定有关,但是我正在寻找有关类型系统在此处执行操作的准确描述。

杰弗里·斯科菲尔德

一种看待它的方法是您的字段state不能具有您赋予它的多态值,因为可变值不能是多态的。引用最多是单态的(如'_a类型变量符号所示)。

如果只是尝试在顶级中声明类似的引用,则会看到相同的效果:

# let lfr: ('a list -> 'a option) ref = ref (fun x -> None);;
val lfr : ('_a list -> '_a option) ref = {contents = <fun>}

类型变量'_a指示尚未确定的某种单一类型。

引用不能是多态的原因是它不健全。如果允许引用是广义的(多态的),则很容易产生出严重错误的程序。(实际上,这通常意味着崩溃和核心转储。)

关于健全性的问题,将在本文开始时进行讨论:雅克·加里格Jacques Garrigue),放宽价值限制(我忘记了事物的工作原理时会定期提及)。

更新资料

我认为您想要的是“等级2多态性”。即,您需要一个类型为多态的字段。实际上,只要声明类型,就可以在OCaml中获得它。通常的方法是使用记录类型:

# type lfrec = { mutable f: 'a. 'a list -> 'a option };;
type lfrec = { mutable f : 'a. 'a list -> 'a option; }
# let x = { f = fun x -> None };;
val x : lfrec = {f = <fun>}
# x.f ;;
- : 'a list -> 'a option = <fun>

以下代码使用lfrec而不是引用为我编译

module M : sig
  type 'a t
  val call : 'a t -> 'a option
end = struct
  type 'a t
  type lfrec = { mutable f: 'a. 'a t -> 'a option }
  let state: lfrec = { f = fun _ -> None }
  let call : ('a t -> 'a option) = fun x -> state.f x
end

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章