为啥 OCaml 模式匹配比 Erlang 弱?

Posted

技术标签:

【中文标题】为啥 OCaml 模式匹配比 Erlang 弱?【英文标题】:Why is OCaml's pattern matching weaker than Erlang's?为什么 OCaml 模式匹配比 Erlang 弱? 【发布时间】:2016-04-29 14:27:03 【问题描述】:

我是 OCaml 的新手,正在阅读 Real World OCaml (RWO) 书籍。模式匹配在第 3 章中进行了描述,与 Erlang(或 Prolog)的模式匹配相比似乎很弱。

我的问题是:

    为什么 OCaml 的模式匹配较弱? OCaml 的模式匹配风格有什么优势吗?

一个具体的例子:

以下函数(取自 RWO 第 63 页)对列表进行去扰

let rec destutter list =
    match list with
    | [] -> []
    | [hd] -> [hd]
    | hd :: hd' :: tl ->
      if hd = hd' then ds1 (hd' :: tl)
      else hd :: ds1 (hd' :: tl)
  ;;

# destutter [1;2;3;3;4;5;5;6];;
- : int list = [1; 2; 3; 4; 5; 6]

在 Erlang 中,可以(而且我认为更可取)使用模式匹配而不是条件匹配:

destutter([])      -> [];
destutter([X])     -> [X];
destutter([H,H|T]) -> destutter([H|T]);
destutter([H|T])   -> [H | destutter(T)].

在 OCaml 中尝试这种事情......

let rec destutter list =
    match list with
    | [] -> []
    | [hd] -> [hd]
    | hd :: hd :: tl -> destutter tl  (* error *)
    | hd :: tl -> hd :: destutter tl
  ;;

... 在标记的行上引发错误:

Error: Variable hd is bound several times in this matching

因此,Erlang/Prolog 样式的模式匹配在 OCaml 中不起作用。为什么? OCaml 方法的优点是什么?

感谢和祝福

伊万

【问题讨论】:

【参考方案1】:

首先,您始终可以通过 OCaml 中的 when 子句捕获模式变量之间的相等性,例如:

let rec destutter = function
    | []              -> []
    | [hd]            -> [hd]
    | hd :: hd' :: tl
      when hd = hd'   -> destutter (hd :: tl)
    | hd :: hd' :: tl -> hd :: destutter (hd' :: tl)

这里有一个权衡。虽然 Erlang 更具表现力,但 OCaml 模式匹配更简单(这意味着更简单的语言定义、编译器等),并且您仍然可以做您需要的事情(以编写更多代码为代价)。

请注意,虽然您可以使用 when 子句将非线性模式重写为线性模式,但这不是主要问题。更关键的是,模式匹配需要对任意类型有一个相等的概念,以支持非线性模式。这在 Erlang 中不是问题,但 OCaml 不仅已经内置了 === (结构平等与身份),而且对于任何给定类型,它可能不是您需要的那种平等(例如,考虑字符串和区分大小写)。然后,因此,检查详尽或重叠变得不平凡。最后,考虑到模式的各个部分之间可能存在多少有用的关系,是否值得为一种特定类型的相等提供特殊情况是值得怀疑的。 (我注意到非严格语言还有其他问题。)

顺便说一句,Prolog 的模式匹配是基于统一的,并且比 Erlang 或 OCaml 更强大(但也更难实现)。

【讨论】:

感谢您的回答!三个非常好的答案,很难决定接受哪个。 -- when 子句在 Erlang 中也可用(称为守卫)。 RWO 书中稍后会出现一个与您类似的示例,但我会想念 Erlang 风格的 PM :(【参考方案2】:

OCaml 中的模式被编译成具有大量sophisticated optimizations 的非常高效的代码。 Bjarne Stroustrup 甚至 bragged 他们设法在某些情况下用 C++ 编写了类似的东西。但总的来说,OCaml 模式匹配要快得多。看看汇编输出很有趣。也许 Erlang 提供了更多的灵活性,但这是一种动态语言所期望的。否则,为什么要使用它们。

还有另一个问题。模式在结构上是匹配的。如果你想匹配[H,H|T],你实际上是在调用前两个元素的比较。大多数情况下,比较功能应该是用户自己提供的,事先并不知道。

【讨论】:

【参考方案3】:

Erlang 模式更强大,因为它可以匹配在运行时确定的内容。 OCaml 模式与编译时固定的内容相匹配。因此,OCaml 模式可能会变得更快。我还发现 OCaml 样式的模式更容易推理。

【讨论】:

感谢您的回答!三个非常好的答案,很难决定接受哪个。 -- 你发现OCaml 风格的模式更容易推理,因为你对OCaml 比对Erlang 更熟悉?我如何才能爱上来自 Erlang 的 OCaml PM?

以上是关于为啥 OCaml 模式匹配比 Erlang 弱?的主要内容,如果未能解决你的问题,请参考以下文章

在 Erlang 中进行模式匹配映射时,为啥这个变量是未绑定的?

OCaml 中的模式匹配和嵌套模式匹配

Ocaml模式匹配“方形”元组?

Ocaml模式匹配:为什么不使用此匹配?

OCaml:在另一个内部匹配表达式?

OCaml 中的弱多态性