递归& F#的不变性

时间:2014-02-12 20:01:46

标签: recursion f#

考虑以下简单示例:

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 }

此定义将导致编译器错误。我的问题如下:有没有什么方法可以使上面的绑定没有诉诸反射或可变字段?

2 个答案:

答案 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尚未完全定义,因此无法定义此闭包。