Вы можете опустить метки, если приложение является полным (т. Е. Все обязательные аргументы предоставлены) и , если возвращаемый тип функции не является переменной типа. Аргументы необязательных параметров всегда должны передаваться меткой.
Давайте сделаем несколько примеров,
let example1 ?(opt=0) ~a ~b ~c unlabeled =
opt + a + b + c + unlabeled;;
example1 1 2 3 4;;
- : int = 10
Здесь мы смогли применить все аргументы без меток, потому что мы предоставили все обязательные аргументы (необязательный параметр не обязателен, отсюда и название)и полученный тип не является полиморфным. Однако, если мы возьмем функцию List.fold
из Core или ListLabels, которая имеет тип
'a list -> init:'accum -> f:('accum -> 'a -> 'accum) -> 'accum
, тогда мы получим
List.fold [1;2;3;4] 0 (+);;
- : init:(int -> (int -> int -> int) -> '_weak1) ->
f:((int -> (int -> int -> int) -> '_weak1) ->
int -> int -> (int -> int -> int) -> '_weak1) ->
'_weak1
вместо 10
, чтобудет ожидать. Причина этого в том, что результирующий тип 'accum
является переменной типа, поэтому он также может быть функцией, например, int -> int
или string -> int -> unit
и т. Д. - все эти типы соответствуют типу 'accum
. В основном это означает, что эта функция принимает потенциально бесконечное количество позиционных аргументов. Следовательно, все аргументы, которые мы предоставили, были интерпретированы как позиционные, и в результате мы никогда не могли заполнить помеченные аргументы, поэтому наше приложение не было полным. Это фактически делает наше первоначальное определение правила в начале публикации избыточным - поскольку приложение, тип которого обозначен переменной типа, никогда не может быть полным.
Обратите внимание, что эта проблема возникает только в том случае, если возвращаемый тип является переменной типа, а не только включает в себя некоторые переменные типа, например, мы можем легко опустить метки с помощью функции List.map
, например, с учетом List.map
из Core, который имеет тип
'a list -> f:('a -> 'b) -> 'b list
, мы можем легко применить его
# List.map [1;2;3] ident;;
- : int Core_kernel.List.t = [1; 2; 3]
Несмотря на все сказанное, обычно считается плохой практикой опускать метки. Главным образом из-за предостережений с полиморфными типами возвращаемых данных и потому, что это делает важным порядок помеченных аргументов, что является своего рода нелогичным.