【问题标题】:pattern-match on big type, a way to reduce the size of the code大类型上的模式匹配,一种减少代码大小的方法
【发布时间】:2018-07-20 19:46:27
【问题描述】:

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

    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» 那样进行模式匹配(对参数数量进行模式匹配以减少案例数量)。

谢谢!

【问题讨论】:

  • 报错信息很奇怪,OCaml好像以为整个程序写在一行上。你用的是哪个编辑器?你在 Windows 上工作吗?
  • 你是对的。实际上,它来自于从 pdf 文件中复制和粘贴代码的事实。所以小编觉得整个程序写在一行里

标签: functional-programming ocaml


【解决方案1】:

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

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

【讨论】:

  • 谢谢!它确实完美地回答了我的问题。但是为什么我不能在这里使用析取运算符?
  • 上下文需要pattern,而||infix operator 中的expression。在任何情况下,|| 的类型都是 bool -> bool -> bool(不是 formule -> formule -> ?)。
【解决方案2】:

在你的情况下,我会像这样重构 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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-24
    • 2011-05-05
    • 2021-08-29
    • 2017-12-22
    • 1970-01-01
    • 2020-10-17
    • 2013-04-09
    • 1970-01-01
    相关资源
    最近更新 更多