Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In OCaml, what is the canonical way of matching against multiple arguments of a function?

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.

like image 726
Pteromys Avatar asked Nov 27 '11 13:11

Pteromys


People also ask

How does match work in OCaml?

Pattern matching comes up in several places in OCaml: as a powerful control structure combining a multi-armed conditional, unification, data destructuring and variable binding; as a shortcut way of defining functions by case analysis; and as a way of handling exceptions.

What is a tuple in OCaml?

Every function in OCaml takes exactly one value and returns exactly one result. For instance, our squareRoot function takes one float value and returns one float value. The advantage of always taking one argument and returning one result is that the language is extremely uniform.


2 Answers

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).

like image 150
Martin Jambon Avatar answered Nov 30 '22 00:11

Martin Jambon


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).

like image 20
Chris Conway Avatar answered Nov 30 '22 02:11

Chris Conway