数据中的<cycle>是什么?

What is <cycle> in data?

(我用的是OCaml 4.02.3版本)

我定义了一个类型self

# type self = Self of self;;
type self = Self of self 

及其实例s

# let rec s = Self s;;
val s : self = Self <cycle>

因为OCaml is a strict language,我预计定义s会陷入无限递归。但是解释器说 s 有一个值,它是 Self <cycle>.

我也对s应用了一个函数。

# let f (s: self) = 1;;
val f : self -> int = <fun> 
# f s;;
- : int = 1 

似乎 s 在函数应用之前没有被评估(就像在非严格语言中)。

OCaml 如何处理像 s 这样的循环数据? Self <cycle>是正规形式吗?

OCaml 确实是一种急切的语言,但是 s 是一个完全有效且经过充分评估的术语,恰好包含一个循环。例如,此代码产生预期结果:

let f (Self Self x) = x
f s == s;; 

更准确地说,具有 n 个参数的构造函数的内存表示被装箱并读取如下:

⋅—————————————————————————————————————————————⋅
| header | field[0] | field[1] | ⋯ | fiekd[n] |
⋅—————————————————————————————————————————————⋅

header 包含元数据,而 field[k] 是一个 OCaml 值,即整数或指针。在 s 的情况下,Self 只有一个参数,因此只有一个字段 field[0]field[0] 的值只是指向块开头的指针。因此,术语 s 在 OCaml 中可以完美表示。

此外,顶层打印机能够检测到这种循环并打印一个<cycle>以避免在打印s的值时陷入无限递归。在这里,<cycle><abstr><fun> 一样,只是表示一种顶层打印机无法打印的值。

但是请注意,循环值在很多情况下会触发无限递归,例如f s = s,其中(=)是结构等式 而不是物理 (i.e. (==)) 触发这种递归,另一个例子是

let rec ones = 1 :: ones;; (* prints [1;<cycle>] *)
let twos = List.map ((+) 1) ones;; (* falls in an infinite recursion *)