在 OCaml 中,匹配函数的多个参数的规范方法是什么?

发布于 2024-12-18 09:03:38 字数 465 浏览 2 评论 0原文

您可以通过创建一个元组然后在匹配表达式中解构它来对函数的多个参数进行模式匹配:

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

或者,如果您不需要柯里化函数,您可以通过创建 f 来实现此目的将元组作为唯一参数:

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

后一种方法的优点是每次定义函数时不必将参数写入两次。但采用元组的函数似乎没有柯里化函数那么流行。

那么,在 OCaml 社区中,两者中哪一个被认为是规范的或首选的呢?

编辑:正如 pad 在下面指出的那样,我的意思是第二个代码片段中的 let f = function blah blah

You could pattern-match against multiple arguments of a function by creating a tuple and then destructuring it in a match expression:

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

Alternatively, if you don't need a curried function, you could do this by making f take a tuple as the only argument:

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

The advantage of the latter method is that you don't have to write the arguments twice every time you define a function. But functions that take a tuple seems to be not as popular than curried ones.

So which of the two is deemed canonical, or preferred, in the OCaml community?

EDIT: Just as pad pointed out below, I mean let f = function blah blah in the second code snippet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

恋竹姑娘 2024-12-25 09:03:38

这个解决方案是规范的:

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

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

This solution is canonical:

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

The compiler optimizes this special case and does not actually allocate a block for the tuple (x, y).

扮仙女 2024-12-25 09:03:38

元组不仅仅是一个语法结构,它代表了一个真实的数据结构。这意味着在 xy 的情况下,fun (x,y) 的效率(非常轻微)低于 fx 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

由于这个原因,通常最好避免使用元组作为函数参数,除非您有充分的理由这样做。

PS 类似的考虑也适用于数据类型声明,其中以下内容略有不同:

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

Foo 是一个带有两个参数的数据类型构造函数。 Bar 是一个带有一个参数(一个元组)的构造函数。

A tuple is not just a syntactic construct, it represents a real data structure. This means that fun (x,y) is (very slightly) less efficient than f x y in the case were x and y aren't already tupled, because a tuple has to be allocated. If this isn't clear, the rough equivalent in Java would be

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

For this reason, it's generally preferable to avoid using tuples as function arguments unless you have a good reason to do so.

P.S. A similar consideration applies to datatype declarations, where the following are subtly different:

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

Foo is a datatype constructor that takes two arguments. Bar is a constructor that takes one argument (a tuple).

落日海湾 2024-12-25 09:03:38

实际上,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... 构造变得更加重要。

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

Actually, f = function... is a shortcut of f (x, y) = match (x, y) with... so:

let f = function 
  | pattern1_of_x_y -> expr1
  | ...

is the same as:

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

(Notice that there is a mistake in your second formulation; those two versions are not compatible).

As you pointed out, one cannot avoid using match ... with... in a curried function. Personally, I prefer the curried form of a function since it is more flexible, especially with partial application. Moreover, pattern matching is not only applied in function arguments; they are used essentially everywhere in OCaml, which makes match ... with... construct even more important.

Whenever you spot the usage pattern as above, try to replace match ... with... with function. It is just a matter of style, so there is nothing more prefered here.

水晶透心 2024-12-25 09:03:38

规范的方法是柯里化函数并在元组(即您的第一个片段)上进行匹配。

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

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

The canonical way is a curried function and to match on the tuple, i.e. your first snippet.

This is the way the standard library is written (look at the standard library sources, for example many functions in list.ml).

This is also the way that the implementation is optimized for, especially the native code compiler. If you create a tuple or other block and destroy it immediately without passing it to functions that expect a block, the native code compiler often spots that and avoids allocating a block altogether. Even if you end up allocating a block, it's more efficient to make the duration of the block as short as possible, to increases the chances that the block remains in the minor heap and in the processor cache.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文