再帰参照が遅延していない場合 (たとえば、関数または遅延値でラップされている場合)、これを直接行うことはできません。「一気に」すぐに参照して値を作成する方法がないというのが動機だと思うので、これは理論的な観点からは厄介です。
ただし、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
ジェームズが述べたように、これを行うことが許可されていない場合は、データ構造をウォークするプログラムが終了するなど、いくつかの優れたプロパティを持つことができます (データ構造は制限されており、再帰できないため)。したがって、再帰的な値にはもう少し注意する必要があります:-)