2012-08-26 140 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