如何使用单根建模简单层次结构

Dav*_*vre 7 f#

我想在F#中建模一个层次结构,其中每个节点必须有一个父节点,显然是根节点,它没有父节点.我天真的解决方案

type Node = {
    Id: int // meta data for node
    Parent: Node option
}
let root = { Id = 1; Parent = None}
let child1 = { Id = 2; Parent = Some(root)}
let child2 = { Id = 3; Parent = Some(child1)}
Run Code Online (Sandbox Code Playgroud)

但是我进入F#已经通过@swlaschin而且他在创建描述性域名时让我大吃一惊.因此Parent,当我有99%的时间需要时,这对我来说是一种选择.我尽力而为:

type Node = 
    | Node of NodeMeta * Node
    | Root of NodeMeta
and NodeMeta = {
    Id: int
}
let root = Root({Id = 1})
let child1 = Node({Id = 2}, root)
let child2 = Node({Id = 3}, child1)
Run Code Online (Sandbox Code Playgroud)

有更惯用的方式吗?

Aar*_*ach 7

如果我在域驱动设计中为我自己的模型构建这个,我可能会定义节点如下:

[<Struct>] type NodeId = private NodeId of int

module NodeId =
    let create id =
        // Replace with the proper validation rules for a Node Id
        if id < 0
        then Error "NodeId must be non-negative" // I would actually use a DU with each error case
        else Ok <| NodeId id

    let value (NodeId id) = id

type [<Struct>] RootNode = {Id: NodeId}
type [<Struct>] ChildNode = {Parent: Node; Id: NodeId}

and Node =
    | Root of RootNode
    | Node of ChildNode
    member node.Id =
        match node with
        | Root r -> r.Id
        | Node n -> n.Id
    member node.Parent =
        match node with
        | Root _ -> None
        | Node n -> Some n.Parent
    member node.IsRootNode =
        match node with
        | Root _ -> true
        | Node _ -> false
    member node.IsChildNode = 
        not node.IsRootNode
Run Code Online (Sandbox Code Playgroud)

这给了我们以下内容:

  • 用于NodeId该包装的类型int和附带的模块,该模块封装了有效标识符的所有业务规则
  • 特定类型for RootNodeChildNode允许它们仅具有该类型节点的必需字段
  • 一种Node允许我们表示RootNodeChildNode作为相同类型而不要求它们具有相同字段但仍提供对底层字段的直接访问并允许我们轻松区分RootNodes和ChildNodes的单一类型

然后,我会有一个用于创建Nodes 的模块:

module Node = 
    let createRoot = 
        NodeId.create >> Result.bind((fun id -> Root {Id = id}) >> Ok)

    let createChild parent =
        NodeId.create >> Result.bind((fun id -> Node {Id = id; Parent = parent}) >> Ok)
Run Code Online (Sandbox Code Playgroud)