2012-08-26 172 views
0

我有一個簡單的類型是這樣的:樹狀結構,F#泛型

/// <summary> 
/// An attribute consists of a key and all possible values. 
/// </summary> 
type IAttribute<'a when 'a: comparison> = 
    abstract Key: string 
    abstract Values: seq<'a> 

從這個定義我創建像這樣實現:

let numericAttribute values = 
    { new IAttribute<float> with 
     member this.Key = "Numeric" 
     member this.Values = values } 

let enumerationAttribute values = 
    { new IAttribute<string> with 
     member this.Key = "Enumeration" 
     member this.Values = values } 

例子:

let numAttr = numericAttribute [| 1.0; 4.0; 6.0; 20.0; 70.0 |] 
let enAttr = enumerationAttribute [| "val1"; "val2"; "val3" |] 

現在我可以創建實例:

let num1 = new AttributeInstance<float>(numAttr, 4.0) 
let num2 = new AttributeInstance<float>(numAttr, 6.0) 
let en1 = new AttributeInstance<string>(enAttr, "val1") 

AttributeInstance是一種類型,它只是特定屬性類型的元組以及與該屬性類型兼容的值。

我想沿着這行簡單的樹:

type Tree<'a when 'a: comparison> = 
| Leaf of 'a 
| SubTree of AttributeInstance<'a> * seq<Tree<'a>> 

我的問題是,在不同層次樹的我希望能夠有不同的類型。在一個層次上,我希望有一個子樹,其屬性是en1,而在下一級,我希望能夠擁有num1(或num2)。

有人可以幫助我概括或重新考慮這個嗎?

回答

3

的問題是,如果你嘗試寫類似

|Subtree of 'a * seq<Tree<'b>> 

'b最終成爲一種新型的可以創造這樣的它的編譯器不支持類型的無限鏈。要做到這一點可能是包裹可能的類型在聯盟

一種方式 - 喜歡的東西

type Element = 
    |.... 

,然後你的樹變成

type Tree = 
| Leaf of Element 
| SubTree of AttributeInstance<element> * seq<Tree> 

或者,你可以有一個多通用樹 - 類似於

type Tree<'a,'b,'c,'d> = 
| Leaf1 of 'a 
| Leaf2 of 'b 
... 
| SubTree of AttributeInstance<'a> * seq<Tree<'a,'b,'c,'d>> 
+0

+1 - 經過很多FsEye樹結構的實際經驗(其中h反映了OP的設計要求),我決定選擇你建議在工會中包裝可能的類型,並且它已經很好地實現了,它是靈活性和靜態類型安全性的良好平衡。請參閱http://code.google.com/p/fseye/source/browse/trunk/FsEye/WatchModel.fs?r=409 –

+0

聯合解決方案似乎是最直接,最「功能性」的方法。我其實自己想到了多種通用版本,但我不想將自己限制爲固定數量的類型。謝謝! – UmaN