在F#中将参数添加到已区分的联合用例中时,“此声明中不允许使用匿名类型变量”错误

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,在表达式周围添加(讨厌的)双括号,但似乎没有任何效果。

Wal*_*lly 6

回答编译器错误问题

这不会编译...

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)