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

时间:2019-05-23 10:32:15

标签: f# discriminated-union

因此,我有一些(我认为很不寻常)用于构建功能树的代码。现在是这里:

type FunctionTree<'Function> =
    | BranchNode of seq<FunctionTree<'Function>>
    | Leaf of (a:'Function -> unit) with
        member __.Execute() = do a

表达式a:'Function -> unit是使编译器适合的原因,给我错误消息“此声明中不允许使用匿名类型变量”,我也不知道为什么。我尝试将变量添加到BranchNode,在表达式周围添加(讨厌的)双括号,但似乎没有任何效果。

1 个答案:

答案 0 :(得分:6)

回答编译器错误问题

这无法编译...

Leaf of (a:'Function -> unit)

...因为在DU案例中,可以将已区分的字段名称添加到DU案例的类型中,而不是添加到功能类型的类型中。相反,它会编译...

Leaf of a: ('Function -> unit)

...因为使用字段名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

...,该成员向左移动以说明其适用于整个联合,而不仅适用于叶子情况。这就解释了为什么上面的代码现在有不同的编译器错误... a is not defined。字段名称a用于阐明Leaf实例的实例化。字段名称a在其他位置不可用。

let leaf = Leaf(a: myFunc)

因此,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

在上面的代码中,请注意x的值是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