(我使用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>
是正常形式吗?
答案 0 :(得分:4)
OCaml确实是一种渴望的语言,但s
是一个完全有效且完全评估的术语,恰好包含一个循环。例如,此代码产生预期结果:
let f (Self Self x) = x
f s == s;;
更确切地说,具有n个参数的构造函数的内存表示被加框并读取如下:
⋅—————————————————————————————————————————————⋅
| header | field[0] | field[1] | ⋯ | fiekd[n] |
⋅—————————————————————————————————————————————⋅
标头包含元数据,而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 *)