2014-02-12 5 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 еще не полностью определено.

Смежные вопросы