В OCaml, каков канонический способ сопоставления с несколькими аргументами функции? - PullRequest
8 голосов
/ 27 ноября 2011

Вы можете сопоставить шаблон с несколькими аргументами функции, создав кортеж и затем деструктурируя его в выражении соответствия:

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 во втором фрагменте кода.

Ответы [ 4 ]

10 голосов
/ 27 ноября 2011

Это решение каноническое:

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

Компилятор оптимизирует этот особый случай и фактически не выделяет блок для кортежа (x, y).

9 голосов
/ 27 ноября 2011

Кортеж - это не просто синтаксическая конструкция, он представляет собой реальную структуру данных.Это означает, что fun (x,y) (очень немного) менее эффективен, чем f x y в том случае, если 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

. По этой причине обычно предпочтительнее избегать использования кортежей в качестве аргументов функции, если у вас нет веских причин для этого.

PS Аналогичное соображение применимо к объявлениям типов данных, где следующее несколько незначительно отличается:

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

Foo - конструктор типа данных, который принимает два аргумента.Bar - это конструктор, который принимает один аргумент (кортеж).

5 голосов
/ 27 ноября 2011

На самом деле, 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.Это просто вопрос стиля, поэтому здесь нет ничего более предпочтительного.

3 голосов
/ 27 ноября 2011

Канонический способ - это функция с каррированием и match для кортежа, т. Е. Вашего первого фрагмента.

Это способ написания стандартной библиотеки (посмотрите на источники стандартной библиотеки, например, многиефункции в list.ml).

Это также способ оптимизации реализации, особенно компилятора собственного кода.Если вы создаете кортеж или другой блок и уничтожаете его немедленно, не передавая его функциям, ожидающим блок, компилятор собственного кода часто обнаруживает это и избегает выделения блока вообще.Даже если вы в конечном итоге выделяете блок, более эффективно сделать продолжительность блока как можно короче, чтобы увеличить вероятность того, что блок останется в младшей куче и в кэше процессора.

...