您可以通过创建元组然后在匹配表达式中对其进行解构来对函数的多个参数进行模式匹配:
let f x y =
match x, y with
| pattern1 -> expr1
| ...
或者,如果您不需要curried函数,可以通过使f
将元组作为唯一参数来实现:
let f (x, y) = function
| pattern1 -> expr1
| ...
后一种方法的优点是每次定义函数时都不必编写两次参数。但是,采用元组的函数似乎不像咖喱那样受欢迎。
那么在OCaml社区中,哪两个被认为是规范的或首选的?
编辑:正如下面指出的pad,我的意思是第二个代码段中的let f = function blah blah
。
答案 0 :(得分:10)
这个解决方案是规范的:
let f x y =
match x, y with
| pattern1 -> expr1
| ...
编译器优化了这种特殊情况,并没有为元组(x, y)
实际分配块。
答案 1 :(得分:9)
元组不仅仅是一个语法结构,它代表了一个真实的数据结构。这意味着fun (x,y)
在f x y
x
的情况下效率(非常轻微)低于y
且void foo(X x, Y y) { ... }
void bar(Tuple<X,Y> t) { ... }
/* client code */
X x = new X();
Y y = new Y();
foo(x, y); // Just uses x and y directly
bar(new Tuple<X,Y>(x, y)); // Has to "new" a Tuple
尚未被置换,因为必须分配元组。如果不清楚,Java中的粗略等价物将是
type 'a foo = Foo of 'a * 'a;
type 'a bar = Bar of ('a * 'a);
出于这个原因,通常最好避免使用元组作为函数参数,除非你有充分的理由这样做。
P.S。类似的考虑也适用于数据类型声明,其中以下内容略有不同:
Foo
Bar
是一个带有两个参数的数据类型构造函数。 {{1}}是一个构造函数,它接受一个参数(一个元组)。
答案 2 :(得分:5)
实际上,f = function...
是f (x, y) = match (x, y) with...
的捷径,所以:
let f = function
| pattern1_of_x_y -> expr1
| ...
与:
相同let f (x, y) =
match x, y with
| pattern1 -> expr1
| ...
(请注意,您的第二个配方中存在错误;这两个版本不兼容)。
正如您所指出的那样,人们无法避免在curry函数中使用match ... with...
。就个人而言,我更喜欢功能的curry形式,因为它更灵活,特别是部分应用。而且,模式匹配不仅应用于函数参数;它们在OCaml中基本上被使用,这使得match ... with...
构造得更加重要。
每当您发现上述使用模式时,请尝试将match ... with...
替换为function
。这只是风格问题,所以这里没有更多的选择。
答案 3 :(得分:3)
规范方式是一个curry函数和元组上的match
,即你的第一个片段。
这是标准库的编写方式(查看标准库源代码,例如list.ml
中的许多函数)。
这也是实现优化的方式,尤其是本机代码编译器。如果您创建一个元组或其他块并立即将其销毁而不将其传递给期望块的函数,则本机代码编译器通常会发现它并避免完全分配块。即使您最终分配了一个块,使块的持续时间尽可能短也更有效,从而增加了块保留在次要堆和处理器缓存中的可能性。