match
and if
具有不同的语义:match
是平行的,if
是严格顺序的。如果你有表情:
match expr with
| A -> e1
| B -> e2
| C -> e3
| ...
然后它可以按任何顺序比较分支。在我提供的示例中,它可以编译为二分搜索,利用构造函数表示为普通数字的事实。
在表达式中
if e1 then e2 else if e3 then e4 else ...
这是语言语义所要求的,即e3
经过严格评估后e1
和当且仅当e1
被评估为 false。这意味着,编译器无法重新排列比较顺序,因为它不知道是否e1
is true
of false
(如果它知道,那么 if 表达式将通过常量折叠进行修剪,所以没关系)。
回到你的例子。如果编译您的匹配函数,您将得到以下代码(在 x86_64 上):
.L104:
cmpq $5, %rax
jbe .L103
addq $2, %rax
ret
.L103:
sarq $1, %rax
cmpq $1, %rax
je .L101
jg .L100
.L102:
movq $3, %rax
ret
.L101:
movq $5, %rax
ret
.L100:
movq $7, %rax
ret
这实际上对应于表达式:
if x > 2 then x + 1
else match compare x 1 with
| 0 -> 2
| 1 -> 3
| _ -> 1
非常高效的代码,只使用两次比较。在运行时,它通常(取决于数据分布)以一次比较结束。
如果你编译一个例子if
然后它会发出基本上等于原始 OCaml 代码的代码。因为,根据语义,编译器需要这样做if
表达。if
表达must是连续的。
人们可以争辩说,if
例如,假设比较函数是内置比较函数,则可以编译为相同的代码。但为此,编译器需要证明比较函数是内置的或没有副作用。仅针对一种特定情况int
。我怀疑有人会编写这样的优化,因为它不值得。
其他显着特征match
表达式的特点是匹配可以在一组非常有限的对象上执行,这些对象有一个共同点,它们都是序数,或者可以排序。在if
表达式,我们有任意表达式。