如果遞歸引用沒有延遲(例如包裝在函數或惰性值中),則不能直接執行此操作。我認爲動機是,沒有辦法立即引用「立即」創造價值,因此從理論角度來看,這將是尷尬的。但是,F#支持遞歸值 - 如果遞歸引用被延遲(F#編譯器將生成一些初始化數據結構並填充遞歸引用的代碼),則可以使用這些值。最簡單的方法就是換一個懶惰的值內refernece(功能將工作太):
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
正如詹姆斯所說,如果你不能做到這一點,你可以有一些很不錯的屬性如能走動的數據結構將終止任何程序(因爲數據結構是有限的,不能遞歸)。因此,您需要對遞歸值進行更謹慎的處理:-)
你能對這個問題展開,對於那些不會說太多Python的人呢?你的類型定義看起來很好,但是請注意F#不允許直接構造一個判別聯合類型(例如樹)......只能構造聯合值;例如Node,如「let x = Node(0,[])」或「let y = Node(1,[x])」,其中[]是空列表。 – 2010-06-21 16:43:31
@詹姆斯:他想創建一個屬於自己孩子的節點。像'let rec x = Node(東西,[x])'(除了不起作用)。 – sepp2k 2010-06-21 16:47:38
@ sepp2k:這通常會爲列表中的任何代碼創建一個無限循環,儘管...非常不可取的:-)我已經看到在其他語言中完成標記列表的結束,但爲了這個目的,idomatic F#會使用另一個DU值,例如「None」。 – 2010-06-21 16:51:08