Ответ на вопрос об ошибке компилятора
Это не компилируется ...
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
используется для пояснения случая создания листа. Имя поля 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