我是OCaml的新手并阅读了Real World OCaml(RWO)一书。模式匹配在第3章中描述,与Erlang(或Prolog)的模式匹配相比似乎很弱。
我的问题是:
一个具体的例子:
以下功能(取自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方法有哪些优点?
感谢和祝福
伊万
答案 0 :(得分:10)
首先,您始终可以通过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不仅内置=
vs ==
(结构相等与身份相同),但对于任何给定类型,它可能不是那种平等您需要的(例如,考虑字符串和区分大小写)。然后,结果,检查穷举或重叠变得非常重要。最后,考虑到模式各部分之间有多少有用的关系,为一种特定类型的平等提供特殊情况是否值得,这是值得怀疑的。 (我注意到非严格的语言有其他问题。)
顺便说一下,Prolog的模式匹配是基于统一的,并且比Erlang或OCaml更强大(但也更难以实现)。
答案 1 :(得分:7)
OCaml中的模式被编译成一个非常有效的代码,有很多sophisticated optimizations。 Bjarne Stroustrup甚至bragged他们设法在某些情况下用C ++编写了类似的东西。但总的来说,OCaml模式匹配的速度要快得多。而且看起来装配输出很迷人。也许Erlang提供了更多的灵活性,但它是通过动态语言实现的。否则为什么要使用它们。
还有其他问题。模式在结构上是匹配的。如果你想匹配[H,H|T]
,你实际上正在调用前两个元素的比较。在大多数情况下,比较功能应由用户提供,并且事先不知道。
答案 2 :(得分:6)
Erlang模式更强大,因为它可以匹配运行时确定的内容。 OCaml模式与编译时修复的内容相匹配。因此,OCaml模式可能会变得更快。我也发现OCaml风格的模式更容易推理。