【问题标题】:Modeling complex hierarchies in F#在 F# 中建模复杂的层次结构
【发布时间】:2016-10-07 00:27:03
【问题描述】:

我对 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_Parent 使用了“A 选项”。但是我一直无法弄清楚如何定义 B_Parent 和 D_Parent,因为它们对自身和其他类型的嵌套依赖?

【问题讨论】:

    标签: f#


    【解决方案1】:

    首先,一件非常重要的事情:当你写作时

    type B_Parent = A | B
    

    声明 B_Parent 是一个 DU,它连接了两个先前定义的类型 AB。没有语法。

    上面这行实际上是在定义B_Parent的两个空子类型,它们与原来的AB无关。相当于:

    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,但我认为保持大小写名称一致可能会使事情更具可读性。

    【讨论】:

    • 感谢您的回答 - 我已经实现了它并且工作正常。但我还有另一个问题。
    • 有时我必须修改记录,或将其移动到不同的父级 - 这很容易做到。但是因为 F# 记录是不可变的,所以这会创建一个新记录,但我仍然在内存中留下原始记录。我不知道如何摆脱它?
    • 为什么需要摆脱它?不再使用时让垃圾收集器清理它。
    【解决方案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 questionand 关键字在定义 mutually recursive functions 时也很有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-01
      • 1970-01-01
      • 2012-02-16
      • 1970-01-01
      相关资源
      最近更新 更多