2014-02-12 31 views
7

考虑以下简单的例子:递归和不变性在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 } 

该定义将导致编译器错误要么。我的问题是以下几点:有什么办法可以使上述绑定没有诉诸反射或可变领域?

+1

作为一名F#新手,我很想知道上面代码片段的实际应用是什么。 –

+2

这个例子本身就是我拼凑在一起的无意义的简化。更一般的问题是初始化不可变数据结构的循环实例。 – eirik

回答

15
let rec mkChild i = {Value = i; Parent = parent} 
and parent = { Children = children } 
and children = List.init length mkChild 
+2

那么,究竟是什么限制呢?我在规范中找不到任何东西。 – Daniel

+0

这很漂亮 - 我尝试用列表理解来绑定孩子,并且在这种形式和原始形式上都失败了。 – plinth

+2

做得很好!荣誉给你,先生。 – eirik

0

我不能回答F#,但我肯定是没有办法做到这一点OCaml中这是非常接近的F#。这是一样的定义循环列表:

let rec a = 1 :: 2 :: a; 

在递归对象定义的话,那么你不能有沿递归循环函数调用,因为这意味着调用对象的函数,而没有完全构建。

更确切地说,在您的示例中,您尝试传递给List.init关闭(fun i -> { Value = i ; Parent = parent }),但由于parent尚未完全定义,因此无法定义此关闭。