В ML все функции принимают ровно один аргумент.Но когда нам нужно отправить более одного аргумента, ML интерпретирует аргументы в традиционных скобках как один кортеж , в соответствии с правилом только один аргумент:
fun swap1 (i,j) = (j,i)
: val swap1 = fn : 'a * 'b -> 'b * 'a
ДваВышеуказанные аргументы, разделенные *
, означают, что они являются двухартериальным кортежем.
- swap1 (1,2);
val it = (2,1) : int * int
Даже если переменные кажутся отдельными, они все равно считаются одним аргументом, опять же, кортежем из 2 арностей:
fun swap1a (i : int, j : int) = (j,i)
: val swap1 = fn : int * int -> int * int
Если мы создаем синоним типа с type
, например,
type int_pair = int * int
функции, использующие int_pair
, все еще печатаются как кортежи:
fun swap2 ((i,j) : int_pair) = (j,i)
: val swap2 = fn : int_pair -> int * int
fun swap2a (ip : int_pair) = (#2 ip, #1 ip)
: val swap2a = fn : int_pair -> int * int
fun swap2b (ip : int*int) = (#2 ip, #1 ip)
: val swap2b = fn : int * int -> int * int
MLтакже имеет функции curry , где множественные аргументы curried , что в основном означает, что аргументы принимаются по одному за раз, что, опять же, относится к правилу «только один аргумент».Карринг позволяет нам частично применять функцию к некоторым ее аргументам, оставляя остаточную функцию, которая может быть дополнительно оценена позже.Специальный синтаксис ML для функции, которая использует каррирование, состоит в том, чтобы просто иметь аргументы без заключенных в скобки и разделенных пробелом:
fun swap3 i j = (j,i)
: val swap3 = fn : 'a -> 'b -> 'b * 'a
- swap3 1 2;
val it = (2,1) : int * int
Другая визуализация заключается в создании swap3
с анонимными функциями:
- val swap3a = fn i => fn j => (j,i)
- swap3a 1 2;
val it = (2,1) : int * int
Теперь мы можем представить входящее 1 2
, разрешаемое справа налево (по иронии судьбы левостороннее ) ля лямбда-исчисление:
(fn i => fn j => (j,i))(1,2)
(fn i => (2,i))(1)
(2,1)
Обратите внимание, что fn i =>...
на самом деле принимает функцию в качестве входа , в этом примере выражение анонимной функции fn j =>...
, которое имеет значение (2,i)
.Фактически, дух этого можно сделать в REPL:
- ((fn i => fn j => (j,i)) 1) 2;
val it = (2,1) : int * int
Как говорит комментатор Андреас Россберг (см. Комментарии выше), в большинстве функциональных языков функции с несколькими аргументами используют каррирование.Он отмечает, что использование кортежей является декартовым в смысле декартового произведения.Он также отмечает, что это ортогонально , что в этом контексте может означать, что эти два подхода к обработке нескольких аргументов, кортежа и карри, ортогональны друг к другу, поскольку они полностьюпротивоположные, не перекрывающиеся подходы, которые семантически не мешают друг другу.