考虑以下简单示例:
type Parent = { Children : Child list }
and Child = { Value : int ; Parent : Parent }
let rec children = [ { Value = 0 ; Parent = parent } ]
and parent = { Children = children }
F#编译器足够智能,可以正确初始化这些递归对象,可以通过运行验证
obj.ReferenceEquals(parent, parent.Children.Head.Parent)
现在,请考虑以下概括:
let length = 100 // assume arbitrary
let rec children = List.init length (fun i -> { Value = i ; Parent = parent })
and parent = { Children = children }
此定义将导致编译器错误。我的问题如下:有没有什么方法可以使上面的绑定没有诉诸反射或可变字段?
答案 0 :(得分:15)
let rec mkChild i = {Value = i; Parent = parent}
and parent = { Children = children }
and children = List.init length mkChild
答案 1 :(得分:0)
我无法回答F#
,但我确信在OCaml中没有办法做到这一点,这与F#非常接近。这与定义循环列表相同:
let rec a = 1 :: 2 :: a;
在递归对象定义的情况下,你不能在递归循环中进行函数调用,因为它意味着在尚未完全构造的对象上调用函数。
更准确地说,在您的示例中,您尝试将List.init
传递给(fun i -> { Value = i ; Parent = parent })
,但由于parent
尚未完全定义,因此无法定义此闭包。