如果递归引用没有延迟(例如包装在函数或惰性值中),则不能直接执行此操作。我认为动机是没有办法“立即”通过直接引用来创造价值,所以从理论的角度来看这会很尴尬。
但是,F# 支持递归值 - 如果递归引用被延迟,您可以使用这些值(然后 F# 编译器将生成一些代码来初始化数据结构并填充递归引用)。最简单的方法是将引用包装在惰性值中(函数也可以工作):
type Tree =
| Node of int * Lazy<Tree list>
// Note you need 'let rec' here!
let rec t = Node(0, lazy [t; t;])
另一种选择是使用突变来编写它。然后你还需要使你的数据结构可变。例如,您可以存储ref<Tree>
而不是Tree
:
type Tree =
| Node of int * ref<Tree> list
// empty node that is used only for initializataion
let empty = Node(0, [])
// create two references that will be mutated after creation
let a, b = ref empty, ref empty
// create a new node
let t = Node(0, [a; b])
// replace empty node with recursive reference
a := t; b := t
正如詹姆斯所提到的,如果您不允许这样做,您可以拥有一些不错的属性,例如任何遍历数据结构的程序都会终止(因为数据结构是有限的并且不能递归)。因此,您需要对递归值更加小心:-)