2011-11-27 56 views
7

你可以模式匹配对函数的多个参数创建一个元组,然后在比赛中表现解构它:在OCaml中,匹配函数的多个参数的规范方法是什么?

let f x y = 
    match x, y with 
    | pattern1 -> expr1 
    | ... 

另外,如果你不需要咖喱功能,你可以通过做使f需要一个元组作为唯一的参数:

let f (x, y) = function 
    | pattern1 -> expr1 
    | ... 

后一种方法的优点是,你不必在每次定义一个函数时写的参数两次。但是采用元组的函数似乎不像咖喱类那样受欢迎。

那么哪两个在OCaml社区被视为规范或首选?

编辑:正如垫指出下面,我的意思是let f = function blah blah在第二个代码段。

回答

8

元组不仅仅是一个语法结构,它代表了一个真正的数据结构。这意味着在xy尚未被元组化的情况下,fun (x,y)(非常轻微)效率低于f x y,因为元组必须被分配。如果这是不明确的,相当于在Java中是

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 

出于这个原因,这是一般最好避免使用元组作为函数的参数,除非你有一个很好的理由这样做。

P.S.类似的考虑适用于数据类型声明,其中以下是微妙的不同:

type 'a foo = Foo of 'a * 'a; 
type 'a bar = Bar of ('a * 'a); 

Foo是一种数据类型构造函数有两个参数。 Bar是一个构造函数,它接受一个参数(一个元组)。

4

其实,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 
    | ... 

(注意这里是你的第二个配方中的错误;这两个版本都没有兼容)。

正如您所指出的,人们不能避免在咖喱功能中使用match ... with...。就我个人而言,我更喜欢功能的咖喱形式,因为它更灵活,特别是在部分应用中。此外,模式匹配不仅适用于函数参数,它们基本上在OCaml中随处可见,这使得match ... with...的构造变得更加重要。

每当您发现上述使用模式时,请尝试用function替换match ... with...。这只是一个风格问题,所以这里没有什么比这更好的了。

8

该解决方案是规范:

let f x y = 
    match x, y with 
    | pattern1 -> expr1 
    | ... 

编译器优化此特殊情况,并且实际上不分配的块为元组(x, y)

3

规范的方式是一个curried函数和match上的元组,即您的第一个片段。

这是标准库的编写方式(查看标准库源代码,例如list.ml中的许多函数)。

这也是实现优化的方式,尤其是本机代码编译器。如果您创建一个元组或其他块并立即销毁它,而不将它传递给期望块的函数,本地代码编译器通常会发现它并避免完全分配块。即使您最终分配了一个块,将块的持续时间尽可能短也会更有效,从而增加块保留在次堆中和处理器高速缓存中的机会。

相关问题