执行OCaml';下划线类型';(例如,';_a)引入运行时类型错误/可靠性冲突的可能性?

执行OCaml';下划线类型';(例如,';_a)引入运行时类型错误/可靠性冲突的可能性?,ocaml,sml,Ocaml,Sml,我读了一些关于标准ML中的值限制的内容,并尝试将示例翻译成OCaml,看看它能做些什么。似乎OCaml在SML由于值限制而拒绝程序的上下文中生成了这些类型。我也在其他上下文中见过它们,比如尚未“专门化”到特定类型的空哈希表 以下是SML中被拒绝的程序的示例: val r: 'a option ref = ref NONE val r1: string option ref = r val r2: int option ref = r val () = r1 := SOME "foo" val

我读了一些关于标准ML中的值限制的内容,并尝试将示例翻译成OCaml,看看它能做些什么。似乎OCaml在SML由于值限制而拒绝程序的上下文中生成了这些类型。我也在其他上下文中见过它们,比如尚未“专门化”到特定类型的空哈希表

以下是SML中被拒绝的程序的示例:

val r: 'a option ref = ref NONE
val r1: string option ref = r
val r2: int option ref = r
val () = r1 := SOME "foo"
val v: int = valOf (!r2)
如果您将第一行逐字输入新泽西州的SML repl,您将得到 出现以下错误:

- val r: 'a option ref = ref NONE;
stdIn:1.6-1.33 Error: explicit type variable cannot be generalized at its binding declaration: 'a
如果不使用显式类型注释,则会得到

- val r = ref NONE

stdIn:1.6-1.18 Warning: type vars not generalized because of
   value restriction are instantiated to dummy types (X1,X2,...)
val r = ref NONE : ?.X1 option ref
这个虚拟类型到底是什么?它似乎完全无法访问,无法与任何东西统一

- r := SOME 5;

stdIn:1.2-1.13 Error: operator and operand don't agree [overload conflict]
  operator domain: ?.X1 option ref * ?.X1 option
  operand:         ?.X1 option ref * [int ty] option
  in expression:
    r := SOME 5
相比之下,在OCaml中,虚拟类型变量是可访问的,并且与它所能做的第一件事相统一

# let r : 'a option ref = ref None;;
val r : '_a option ref = {contents = None}

# r := Some 5;;
- : unit = ()
# r ;;
- : int option ref = {contents = Some 5}
这有点令人困惑,并引发了一些问题

1) 一致性SML实现能否选择使上述“虚拟”类型可访问

2) OCaml如何在没有值限制的情况下保持可靠性?它的担保是否比SML弱

3) 类型
“a option ref
似乎不像
”a option ref
那样多态。为什么不
让r:'a option ref=ref None(带有显式注释)在OCaml中被拒绝

1) 一致性SML实现能否选择使上述“虚拟”类型可访问

修订后的定义(SML97)未规定存在“虚拟”类型;它正式指定的只是
val
不能引入多态类型变量,因为右侧表达式不是非扩展表达式。(也有一些关于类型变量没有泄漏到顶层的评论,但正如Andreas Rossberg在他的文章中指出的,这些评论实际上是关于未确定的类型,而不是定义形式中出现的类型变量,因此它们不能真正作为需求的一部分。)

在实践中,我认为有四种实现方法:

  • 某些实现在类型检查期间拒绝受影响的声明,并强制程序员指定单态类型
  • 一些实现,如MLton,会阻止泛化,但会推迟统一,因此适当的单态类型可以在程序中稍后变得清晰
  • 如您所见,SML/NJ发出警告并实例化一个虚拟类型,该类型随后无法与任何其他类型统一
  • 我想我听说过一些实现默认为
    int
    ?我不确定
虽然“延迟统一”方法确实需要注意确保类型不会与尚未生成的类型名统一,但所有这些选项都可能是允许的,而且显然是合理的(特别是来自函子内部的类型名,因为单态类型可能对应于函子不同应用程序中的不同类型,这当然与常规多态类型有相同的问题)

2) OCaml如何在没有值限制的情况下保持可靠性?它的担保是否比SML弱

我对OCaml不是很熟悉,但从您所写的内容来看,它似乎使用了与MLton相同的方法;因此,它不应该牺牲稳健

(顺便说一句,不管您暗示什么,OCaml确实有值限制。OCaml中的值限制与SML中的值限制之间存在一些差异,但您的代码片段都与这些差异无关。您的代码片段只是演示了在OCaml中如何实施限制与SML的一个实现之间的一些差异)

3) 类型
“a option ref
似乎不像
”a option ref
那样多态。为什么不
让r:'a option ref=ref None(带有显式注释)在OCaml中被拒绝

再说一遍,我对OCaml不是很熟悉,但是-是的,这对我来说似乎是个错误

弱多态类型(
'.
-风格的类型)是一种编程便利,而不是类型系统的真正扩展

2) OCaml如何在没有值限制的情况下保持可靠性?它的担保是否比SML弱

OCaml并没有牺牲值限制,而是实现了一种启发式方法,可以避免系统地注释值的类型,例如
ref None
,其类型仅为“每周”多态性。这是通过查看当前“编译单元”得到的启发:如果它可以确定一个周多态类型的实际类型,那么一切都会像初始声明有适当的类型注释一样工作,否则编译单元将被拒绝,并显示以下消息:

Error: The type of this expression, '_a option ref,
       contains type variables that cannot be generalized
3) 类型“_aoption ref似乎不像”a option ref那样多态。为什么不让r:'a option ref=ref None;;(带有显式注释)在OCaml中被拒绝

这是因为
”a
不是“真实”类型,例如,禁止编写明确定义此“类型”值的签名:

# module A : sig val table : '_a option ref end = struct let option = ref None end;;
Characters 27-30:
  module A : sig val table : '_a option ref end = struct let option = ref None end;;
                             ^^^
Error: The type variable name '_a is not allowed in programs
通过使用递归声明将弱多态变量声明和完成类型定义的后续函数使用打包在一起,可以避免使用这些弱多态类型,例如:

#让recr=ref None并设置x=r:=Some(x+1);;
val r:int选项ref={contents=None}
val集合:整数->单位=

要回答上一个问题的第二部分

3) […]为什么不让r:'a option ref=ref None;;(带有显式注释)在OCaml中被拒绝

这是因为OCaml对类型注释中出现的类型变量有不同的解释:它将它们解释为存在量化的,而不是普遍量化的。就是一种
# let rec r = ref None and set x = r := Some(x + 1);;
val r : int option ref = {contents = None}
val set : int -> unit = <fun>
let n : 'a = 5
let n : 'a. 'a = 5
fun pair (x : 'a) (y : 'a) = (x, y)
let pair : 'a. 'a -> 'a -> 'a * 'a = fun x y -> (x, y)