Gen*_*sis 2 f# discriminated-union
所以我有一些(我假设很不寻常)用于构建功能树的代码。现在是这样:
type FunctionTree<'Function> =
| BranchNode of seq<FunctionTree<'Function>>
| Leaf of (a:'Function -> unit) with
member __.Execute() = do a
Run Code Online (Sandbox Code Playgroud)
该表达式a:'Function -> unit使编译器变得合适,从而给我以下错误:“此声明中不允许使用匿名类型变量”,我也不知道为什么。我尝试将变量添加到BranchNode,在表达式周围添加(讨厌的)双括号,但似乎没有任何效果。
回答编译器错误问题
这不会编译...
Leaf of (a:'Function -> unit)
Run Code Online (Sandbox Code Playgroud)
......因为歧视字段名可以被添加到该类型的DU的情况下,不向类型的函数类型的DU情况。相反,这会编译...
Leaf of a: ('Function -> unit)
Run Code Online (Sandbox Code Playgroud)
...因为使用字段名a来命名类型(Function -> unit)。
有关代码的其他讨论
但是,还有另一个问题。Execute正如您的代码所暗示的那样,您要添加的成员没有被添加到Leaf节点。它被添加到整个功能树中。因此,您将无法a在的实现中访问标签Execute。这样想吧...
type FunctionTree<'Function> =
| BranchNode of seq<FunctionTree<'Function>>
| Leaf of a: ('Function -> unit)
with member __.Execute() = do a
Run Code Online (Sandbox Code Playgroud)
...将该成员向左移动以阐明其适用于整个联合,而不仅仅是叶子情况。这就解释了为什么上面的代码现在有一个不同的编译器错误...... a is not defined。字段名称a用于阐明Leaf实例的实例。该字段名称a在其他位置不可用。
let leaf = Leaf(a: myFunc)
Run Code Online (Sandbox Code Playgroud)
因此,该标签a不适用于您的Execute会员。您需要做这样的事情...
with member x.Execute(input) =
match x with
| BranchNode(b) -> b |> Seq.iter(fun n -> n.Execute(input))
| Leaf(f) -> f(input) |> ignore
Run Code Online (Sandbox Code Playgroud)
请注意,在上面的代码中,该x值为a FunctionTree。
替代实施
我们可以继续前进。但是,我认为以下可能会实现您的目标:
type FunctionTree<'T> =
| BranchNode of seq<FunctionTree<'T>>
| LeafNode of ('T -> unit)
let rec evaluate input tree =
match tree with
| LeafNode(leaf) -> leaf(input)
| BranchNode(branch) -> branch |> Seq.iter (evaluate input)
BranchNode([
LeafNode(printfn "%d")
LeafNode(printfn "%A")
])
|> evaluate 42
Run Code Online (Sandbox Code Playgroud)