我有以下代码(有效):
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
答案 0 :(得分:8)
简而言之,必须在创建引用之前定义引用的类型:
首次定义print
的类型时,您应该可以对其进行注释。
通过交换a
和print
的定义,您使最后一点变得不可能:
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会逃避其作用域