为什么 OCaml 的模式匹配比 Erlang 的弱?

Why is OCaml's pattern matching weaker than Erlang's?

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

我的问题是:

  1. 为什么OCaml的模式匹配较弱?
  2. 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-style 模式匹配在 OCaml 中不起作用。为什么? OCaml 方法的优点是什么?

感谢和祝福

伊万

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

OCaml 中的模式被编译成非常高效的代码,其中包含许多 sophisticated optimizations. Bjarne Stroustrup even bragged,在某些情况下,他们设法在 C++ 中编写出可比的代码。但总的来说 OCaml 模式匹配要快得多。查看程序集输出很迷人。也许 Erlang 提供了更多的灵活性,但这是动态语言所期望的。否则,为什么要使用它们。

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

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

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

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

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

顺便说一句,Prolog 的模式匹配 unification-based 严格来说比 Erlang 或 OCaml 更强大(但也更难实现)。