我对F#相当新,我想在现实世界中对相当复杂的东西进行建模" has-a"关系。在层次结构的顶部有四种类型,A - D,具有以下关系:
A
|
+--A
|
+--B
| |
| +--B
| |
| +--D
| |
| +--D
|
+--C
| |
: +--D
| |
| +--D
:
所以B型可以有一个"父母" A或B的类型,D类型可以具有B,C或D的父级。
我想使用受歧视的联盟来约束每种类型的父级,因此不能将它们分配给无效的父级,例如:
type B_Parent = A | B
type D_Parent = B | C | D
然后我想使用记录来为每种类型建模,其中一个字段是父类,例如:
type A = { parent:A_Parent; ... }
type B = { parent:B_Parent; ... }
type C = { parent:C_Parent; ... }
type D = { parent:D_Parent; ... }
C_Parent不是问题,因为它的父类型A是事先声明的。我已经使用过' A选项'对于A_Parent。但我还没有能够弄清楚如何定义B_Parent和D_Parent,因为它们对自己和其他类型的嵌套依赖?
答案 0 :(得分:5)
首先,一个非常重要的事情:当你写作
type B_Parent = A | B
您不声明B_Parent
是加入两个先前定义的类型A
和B
的DU。没有语法。
上面的行实际上是定义B_Parent
的两个空子类型,它们与原始A
和B
无关。它相当于:
type B_Parent = B_Parent.A | B_Parent.B
为了在DU中重用现有类型,你需要给案例命名 - 有效地将它们包装在另一种类型中。所以适当的声明可以是:
type B_Parent = P_a of A | P_b of B
除此之外 - 正如Anton所说,用于定义相互引用类型的关键字是and
。也就是说,最好保持这种相互参照尽可能小而紧。所以我们可以这样做:
type A = { parent:A_Parent; ... }
and A_Parent = P_a of A
| None
type B = { parent:B_Parent; ... }
and B_Parent = P_a of A
| P_b of B
type C = { parent:C_Parent; ... }
and C_Parent = P_a of A
type D = { parent:D_Parent; ... }
and D_Parent = P_b of B
| P_c of C
| P_d of D
我们可能只使用A option
用于A_Parent
,而A
仅用于C_Parent
,但我认为保持案例名称一致可能会使事情更具可读性。
答案 1 :(得分:2)
您可以使用and
关键字来定义相互关联的类型,例如:
type B_Parent = A | B
and D_Parent = B | C | D
and A_Parent = A
and C_Parent = B
and A = { parent:A_Parent }
and B = { parent:B_Parent }
and C = { parent:C_Parent }
and D = { parent:D_Parent }
另见related SO question。定义mutually recursive functions时,and
关键字也很有用。