以两种不同方式编写函数时,OCaml的奇怪行为

时间:2019-02-24 20:12:39

标签: types ocaml

我有以下代码(有效):

type a = A of int
let print = ref (fun _ -> ())
let f x = !print (A x)

但是以下方法无效:

let print = ref (fun _ -> ())
type a = A of int
let f x = !print (A x)

我想知道为什么交换两行会导致代码无效。

谢谢!

编辑:运行第二个代码时,出现以下错误:

Error: This expression has type a but an expression was expected of type 'a
       The type constructor a would escape its scope

1 个答案:

答案 0 :(得分:8)

简而言之,必须在创建引用之前定义引用的类型: 首次定义print的类型时,您应该可以对其进行注释。 通过交换aprint的定义,您使最后一点变得不可能:

  let print: ( ??? -> unit) ref  = ref (fun _ -> ())
  type a = A of int

此处,???应该为a,但类型a尚未定义。

更确切地说,OCaml中的类型具有作用域,以便检测本地类型何时会逸出定义和有意义的上下文。例如

let x =
  let module M = struct type t = A end in
  M.A

失败,错误与您的第二个示例相同

  

错误:此表达式的类型为M.t,但是期望表达式的类型为'a          类型构造函数M.t会逃避其作用域

在这里,让类型M.t逸出x的定义将是不好的,因为模块M和类型M.t不在外部定义这个定义。

您的示例由于类似的原因而失败。变量

let print = ref (fun _ -> ())

具有类型('_weak1 -> unit) ref,其中'_weak1是仍未知类型的占位符类型。但是,此引用的将来类型现在应该已经存在。

因此,当您定义新类型时

type t = A of int

,然后尝试将此类型分配给'_weak1弱类型变量,

let print': (t -> unit) ref = print

类型检查器抱怨创建类型变量t时类型'_weak1未定义:

  

错误:此表达式的类型为('weak1-> unit)ref          但期望使用类型(t-> unit)ref的表达式          类型构造函数t会逃避其作用域

类似地,您的函数f

 let f x = !print (A x)

暗示!print的类型为t -> unit并导致类似的错误:

  

错误:此表达式的类型为t,但是期望表达式的类型为'weak1          类型构造函数t会逃避其作用域