F# 工会成员的子集为;参数";在模式匹配中

F# 工会成员的子集为;参数";在模式匹配中,f#,discriminated-union,active-pattern,F#,Discriminated Union,Active Pattern,让我们为一棵树定义一个类型,其中包含几种类型的二进制节点,以及其他类型的节点,即 type Tree = | BinaryNodeA of Tree * Tree | BinaryNodeB of Tree * Tree | [Other stuff...] 我想使用一个递归函数来操作这棵树,例如,交换任何类型的二进制节点的子节点(通过构造一个新节点)。让我抓狂的问题是:如何匹配所有的BinaryNodes,使Node flavor成为“一个参数”,以便具有可应用于任何BinaryNode f

让我们为一棵树定义一个类型,其中包含几种类型的二进制节点,以及其他类型的节点,即

type Tree =
| BinaryNodeA of Tree * Tree
| BinaryNodeB of Tree * Tree
| [Other stuff...]
我想使用一个递归函数来操作这棵树,例如,交换任何类型的二进制节点的子节点(通过构造一个新节点)。让我抓狂的问题是:如何匹配所有的BinaryNodes,使Node flavor成为“一个参数”,以便具有可应用于任何BinaryNode flavor的通用交换,以返回该flavor的交换节点

我知道如何使用活动模式匹配所有二进制节点树:

let (|BinaryNode|_|) (tree : Tree) =
    match tree with
    | BinaryNodeA _ | BinaryNodeB _ -> Some(tree)
    | _ -> None
type Flavor = A | B

let (|BinaryNode|_|) (tree : Tree) =
    match tree with
    | BinaryNodeA(x,y) -> Some(A,x,y) 
    | BinaryNodeB(x,y) -> Some(B,x,y)
    | _ -> None

let mkBinaryNode f t1 t2 =
    match f with
    | A -> BinaryNodeA(t1,t2)
    | B -> BinaryNodeB(t1,t2)
但这还不够好,因为以下几点似乎无法实现:

match tree with
| [cases related to unary nodes..]
| BinaryNode a b -> BinaryNode b a

换句话说,我并没有找到使用BinaryNode风格的方法,就好像它是像a和b这样的参数一样。相反,我似乎必须分别匹配每个BinaryNode风格。如果有大量的二进制节点风格,这可能具有实际意义。类型树是Fsyacc/Fslex生成的解析器/lexer的AST,这限制了重构它的选项。有什么想法吗?

您只需要更改活动模式的定义:

let (|BinaryNode|_|) (tree : Tree) =
    match tree with
    | BinaryNodeA _ | BinaryNodeB _ -> Some(tree)
    | _ -> None
type Flavor = A | B

let (|BinaryNode|_|) (tree : Tree) =
    match tree with
    | BinaryNodeA(x,y) -> Some(A,x,y) 
    | BinaryNodeB(x,y) -> Some(B,x,y)
    | _ -> None

let mkBinaryNode f t1 t2 =
    match f with
    | A -> BinaryNodeA(t1,t2)
    | B -> BinaryNodeB(t1,t2)
然后你可以像这样实现你想要的:

match tree with
| [cases related to unary nodes..]
| BinaryNode(f,t1,t2) -> mkBinaryNode f t2 t1

但是,如果这是一种常见的需求,那么改变
树的定义以包含flavor而不是使用活动模式来处理它可能是有意义的。

为什么要为
二进制节点
使用多个构造函数?您能否将其更改为一个单独的构造函数,其中包含一个额外的
标记
成员,该成员对信息进行编码,例如标记*Tree*Tree
二进制节点和
type Tag=a | B
?根据响应,F#无法启用我所寻找的确切方法。因此,我将通过定义Flavor类型和一个具有Flavor定义的BinaryNode联合成员来修改树。这对于这个应用程序来说已经足够了,但我仍然觉得F#语言在这里可以更加灵活。