大类型的模式匹配,这是减少代码大小的一种方法

时间:2018-07-20 19:46:28

标签: functional-programming ocaml

假设我有一个新的“大”类型。 例如,假设我的类型是«formule»:

    type formule =
   |VRAI
   |Predicat of char
   |NON of formule
   |ET of formule * formule
   |OU of formule * formule
   |X of formule
   |G of formule
   |F of formule
   |U of formule * formule

现在,我需要一个可以计算“公式”类型大小的函数。为了做到这一点,我们可以使用相同的算法来计算二叉树的节点数。这里的问题是,如果我执行模式匹配,则必须处理很多情况,这很烦人。

如果我可以像下面的«taille»函数那样对参数的数量进行模式匹配,那将是很好的:

  let rec taille = function
  |VRAI || Predicat(_) -> 1
  |_(a) -> 1 + taille a
  |_(a,b) -> 1 + taille a + taille b

问题是这不起作用。当我编译以下代码时:

type formule =
   |VRAI
   |Predicat of char
   |NON of formule
   |ET of formule * formule
   |OU of formule * formule
   |X of formule
   |G of formule
   |F of formule
   |U of formule * formule

let rec taille = function
  |VRAI || Predicat(_) -> 1
  |_(a) -> 1 + taille a
  |_(a,b) -> 1 + taille a + taille b

我收到以下错误:

File "main.ml", line 1, characters 192-195:
Error: Syntax error

我认为它来自我的模式匹配,这是不正确的,但是在这种情况下,为什么我在第一行出现错误?

此外,如果确实来自我的模式匹配,那么有一种方法可以像«taille»一样进行模式匹配(对参数数量进行模式匹配以减少案例数)。 / p>

谢谢!

2 个答案:

答案 0 :(得分:4)

您不能在这样的模式下使用二进制析取运算符。但是,有一个模式匹配快捷方式可以满足您的需求:

let rec taille = function
  | VRAI | Predicat _ -> 1
  | NON a | X a | G a | F a -> 1 + taille a
  | ET (a, b) | OU (a, b) | U (a, b) -> 1 + taille a + taille b

关于一个和两个参数的情况并不像您希望的那么简洁,但是我认为不可能做得更好。您不能在构造函数上使用通配符(_)。

另一个想法是在辅助函数中捕获“提取参数”模式:

let args = function
  | VRAI | Predicat _ -> []
  | NON a | X a | G a | F a -> [a]
  | ET (a, b) | OU (a, b) | U (a, b) -> [a; b]

然后您可以写:

let rec taille f = List.fold_left (fun a x -> a + taille x) 1 (args f)

或者,没有中间列表:

let fold_args f1 f2 c =
  let rec g = function
    | VRAI | Predicat _ -> c
    | NON a | X a | G a | F a -> f1 (g a)
    | ET (a, b) | OU (a, b) | U (a, b) -> f2 (g a) (g b)
  in
  g

let taille = fold_args (fun x -> 1 + x) (fun x y -> 1 + x + y) 1

答案 1 :(得分:0)

在您的情况下,我将像这样重构类型formule

type infix = ET | OU | U

type prefix = NON | X | G | F

type formule =
  | VRAI
  | Predicat of char
  | Infix of formule * infix * formule
  | Prefix of prefix * formule

我不知道您正在使用的域,但是我想这是带有前缀和中缀运算符的某种语言。

然后您可以像这样编写taille函数:

let rec taille = function
  | VRAI | Predicat _ -> 1
  | Prefix (_, a) -> 1 + taille a
  | Infix (a, _, b) -> 1 + taille a + taille b

现在,您的类型更加精细,您可能会发现对新类型有意义的新功能。