Когда вы можете вызывать функции с помеченными аргументами без меток? - PullRequest
1 голос
/ 10 октября 2019

Кажется, что в определенных ситуациях вы можете вызывать функции с помеченными аргументами без меток, если они находятся в правильном порядке;Например,

let f ~x ~y = Format.sprintf "%d %s" x y;;
f 3 "test";;

работает успешно, но

f "test" 3;;

завершается ошибкой с сообщением об ошибке

Line 1, characters 2-8:
Error: This expression has type string but an expression was expected of type
         int

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

let f ?(x = 1) ~y () = Format.sprintf "%d %s" x y;;
f "help" ();;

успешно, но

f 2 "help" ();;

завершается неудачно с сообщением об ошибке

Line 1, characters 4-10:
Error: The function applied to this argument has type
         ?x:int -> y:string -> string
This argument cannot be applied without label

Существует ли общее правило для случаев, когдаэто возможно?

Ответы [ 2 ]

3 голосов
/ 10 октября 2019

Вы можете опустить метки, если приложение является полным (т. Е. Все обязательные аргументы предоставлены) и , если возвращаемый тип функции не является переменной типа. Аргументы необязательных параметров всегда должны передаваться меткой.

Давайте сделаем несколько примеров,

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]

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

1 голос
/ 10 октября 2019

Да, для этого есть общее правило. Из руководства :

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

Если несколько аргументов функции имеют одинаковую метку (или нет метки), они не будут коммутироваться между собой, ипорядок имеет значение. Но они все еще могут коммутировать с другими аргументами.

В качестве исключения из приведенных выше правил соответствия параметров, , если приложение общее (без всех необязательных аргументов), метки могут быть опущены. На практикемногие приложения являются общими, поэтому метки часто можно опустить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...