Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在OCaml中,放松的值限制何时生效?_Ocaml - Fatal编程技术网

在OCaml中,放松的值限制何时生效?

在OCaml中,放松的值限制何时生效?,ocaml,Ocaml,有人能简单地描述一下放松的价值限制何时生效吗?我很难找到一个简洁明了的规则描述。这是加里格的论文: 但是有点浓。有人知道一个更简洁的来源吗 附录 下面添加了一些很好的解释,但我无法找到以下行为的解释: # let _x = 3 in (fun () -> ref None);; - : unit -> 'a option ref = <fun> # let _x = ref 3 in (fun () -> ref None);; - : unit -> '_

有人能简单地描述一下放松的价值限制何时生效吗?我很难找到一个简洁明了的规则描述。这是加里格的论文:

但是有点浓。有人知道一个更简洁的来源吗

附录

下面添加了一些很好的解释,但我无法找到以下行为的解释:

# let _x = 3 in (fun () -> ref None);;
- : unit -> 'a option ref = <fun>
# let _x = ref 3 in (fun () -> ref None);;
- : unit -> '_a option ref = <fun>
#让x=3英寸(乐趣()->参考无);;
-:unit->“a选项参考=
#让x=ref3 in(fun()->ref None);;
-:unit->'\u a选项参考=

有人能澄清上述情况吗?为什么在封闭let的RHS中对ref的错误定义会影响启发式。

虽然我对这个理论不是很熟悉,但我已经问了一个问题。
加什给我提供了一份工作。该示例只是OCaml映射模块的一部分。看看

也许他能给你一个更好的答案@加什

我不是类型理论家,但以下是我对加里格解释的解释。您有一个值V。从通常的值限制下分配给V的类型(在OCaml中)开始。类型中会有一些单态类型变量(可能为0)。对于仅出现在类型中协变位置的每个此类变量(在函数箭头的右侧),可以将其替换为完全多态类型变量

论点如下。由于您的单态变量是一个变量,您可以想象用任何单一类型替换它。所以你选择了一个无人居住的类型U。现在,因为它只处于协变位置,所以U可以被任何超类型替换。但是每个类型都是未居住类型的超类型,因此可以安全地替换为完全多态变量

因此,当单态变量只出现在协变位置时,放松的值限制开始生效


(我希望我是对的。当然,@gasche会做得更好,正如octref所建议的那样。)

杰弗里直观地解释了为什么放松是正确的。至于什么时候有用,我认为我们可以首先复制答案octref,并将其链接到:

您可以放心地忽略这些微妙之处,直到有一天,您遇到了一个抽象类型的问题,而这个抽象类型并不像您希望的那样多态,然后您应该记住,签名中的协方差注释可能会有所帮助

我们在几个月前讨论过这一点:

考虑以下代码示例:

module type S = sig
  type 'a collection
  val empty : unit -> 'a collection
end

module C : S = struct
  type 'a collection =
    | Nil
    | Cons of 'a * 'a collection
  let empty () = Nil
end

let test = C.empty ()
对于
测试
您得到的类型是
''u a C.collection
,而不是您期望的
'a C.collection
。它不是多态类型(
“\u a
是一个尚未完全确定的单态推理变量),在大多数情况下,您不会满意它

这是因为
C.empty()
不是一个值,所以它的类型不是泛化的(~made-polymorphic)。要从放松的值限制中获益,您必须将抽象类型标记为集合协变:

module type S = sig
  type +'a collection
  val empty : unit -> 'a collection
end
当然,这只是因为模块
C
是用签名
S
密封的:
module C:S=…
。如果模块
C
没有给出明确的签名,类型系统将推断出最普遍的方差(这里是协方差),人们不会注意到这一点

针对抽象接口编程通常是有用的(当定义函子、强制执行幻象类型规程或编写模块化程序时),因此这种情况肯定会发生,了解放松的值限制非常有用

这是一个例子,当您需要了解它以获得更多多态性时,因为您设置了一个抽象边界(具有抽象类型的模块签名),并且它不会自动工作,您必须明确地说抽象类型是协变的

在大多数情况下,当您操作多态数据结构时,这种情况会在未经您注意的情况下发生<代码>[]@[]由于放松,只有多态类型
'a列表


一个具体但更高级的例子是Oleg的Ber MetaOCaml,它使用类型
('cl',ty)代码
来表示分段构建的引用表达式
'ty
表示引用代码的结果类型,
'cl
是一种幻象区域变量,它保证在保持多态性时,引用代码中变量的作用域是正确的。由于在引用表达式是通过组合其他引用表达式(通常不是值)构建的情况下,这依赖于多态性,因此如果没有宽松的值限制,它基本上根本不起作用(这是他优秀但技术性的类型推断中的一个旁注).

补遗中给出的两个示例为什么打字不同的问题让我困惑了好几天。以下是我通过深入研究OCaml编译器的代码所发现的(免责声明:我既不是OCaml方面的专家,也不是ML类型系统方面的专家)

扼要重述 给出了一个单态类型(想想
单位→ α选项ref
,即类型变量
α
未被普遍量化)

直觉
为了进行类型检查,OCaml编译器认为示例(2)和

因此,如果
let
-表达式的主体和所有绑定变量都是值,那么它就是一个值。

在附录中给出的两个示例中,主体是
fun()->ref None
,它是一个函数,因此是一个值。这两段代码之间的区别在于
3
是一个值,而
ref 3
不是。因此,OCaml将第一个
let
视为一个值,而不是第二个值

打字 再次查看OCaml编译器的代码,我们可以看到表达式是否被视为expans
# let _x = 3 in (fun () -> ref None);;        (*  (1)  *)
- : unit -> 'a option ref = <fun>
# let _x = ref 3 in (fun () -> ref None);;    (*  (2)  *)
- : unit -> '_a option ref = <fun>
# let r = ref None in (fun () -> r);;         (*  (3)  *)
- : unit -> '_a option ref = <fun>
let rec is_nonexpansive exp =
  match exp.exp_desc with
    (* ... *)
  | Texp_let(rec_flag, pat_exp_list, body) ->
      List.for_all (fun vb -> is_nonexpansive vb.vb_expr) pat_exp_list &&
      is_nonexpansive body
  | (* ... *)
(* Typing of toplevel expressions *)

let type_expression env sexp =
  (* ... *)
  let exp = type_exp env sexp in
  (* ... *)
  if is_nonexpansive exp then generalize exp.exp_type
  else generalize_expansive env exp.exp_type;
  (* ... *)