Я столкнулся с интересным поведением типа OCaml. Кажется, что машинка не принимает принтер с необязательными аргументами.
Когда функция имеет необязательные аргументы, ее можно ввести как функцию без необязательных аргументов.
(** Simple example *)
let (f1 : ?arg : int -> unit -> int) =
fun ?(arg = 3) () : int -> arg + 5
let f2 : ((unit -> int) -> int) =
fun f -> f ()
let x : int = f2 f1
(* The type of f1 matches the signature of f2 :
the optional argument is well discarded. *)
Здесь f1 имеет необязательный аргумент, но f2 f1 хорошо типизирован. Это потому, что (или, по крайней мере, я так понял) сигнатура аргумента f2 охватывает тип f1. Необязательный аргумент просто отбрасывается.
Однако такое поведение отвергается в принтерах, как показано в этом примере.
(* Data structure *)
type 'a elt = {
data : int;
annot : 'a
}
(* Type of printer annotations *)
type 'annot printer = Format.formatter -> 'annot -> unit
(* Default printer prints nothing *)
let (default : 'a printer) = fun fmt _ -> Format.fprintf fmt ""
(* Generic printer for elts *)
let elt_printer
?(print_annot : 'a printer = default)
(fmt : Format.formatter)
(elt : 'a elt) =
Format.fprintf fmt "%i(%a)"
elt.data
print_annot elt.annot
(* I don't care about printing the annotation *)
let f (elt : _ elt) =
Format.printf
"%a"
elt_printer elt
Вот что возвращает компилятор при использовании elt_printer в вызове fprintf̀:
This expression has type
?print_annot:'a printer -> Format.formatter -> 'a elt -> unit
but an expression was expected of type Format.formatter -> 'b -> unit
Я полагаю, что типографу удается вывести это 'b = 'a elt, но ему не удается отбросить необязательный аргумент.
У меня есть два вопроса относительно этого поведения:
Это ожидаемое поведение машинки для второго примера?
Если нет, существует ли стандартный синтаксис, запрещающий использование функций с необязательными аргументами? Например, есть ли способ запретить использование f1̀ в качестве аргумента f2 в первом примере?
Заранее спасибо.
Обновлено:
Можно принудительно ввести elt_printer без необязательных аргументов, указав его тип.
let f (elt : _ elt) =
Format.printf
"%a"
(elt_printer : _ printer) elt
Обновлено еще раз: Для помеченных аргументов средство ввода строго блокирует преобразования ввода, так как аргументы должны иметь определенное имя. Это не проблема, поднятая в моем вопросе.
Мой вопрос касается разницы между двумя разными поведениями для аналогичного использования функций высокого порядка с необязательными аргументами. Эта тема (хотя и интересная) не дает четкого ответа.





Да, это ожидаемо, функция ?foo -> bar -> baz не может быть преобразована в функцию bar -> baz. Его можно применять только без foo, что сильно отличается от неявного преобразования.
Есть два решения
Во-первых, можно «не применять» метку: f ?print_annot:None сообщит типировщику, что параметр print_annot из f следует считать отсутствующим.
Во-вторых, и это метод, который я использовал для tyxml (посмотреть здесь), вы можете добавить единичный аргумент:
val pp :
?encode:(string -> string) ->
?indent:bool ->
?advert:string ->
unit ->
Format.formatter -> doc -> unit
Тогда у пользователей будет код, который выглядит так:
let s = Format.asprintf "%a" (Tyxml.Html.pp ()) my_html
Спасибо за ответ, но я не уверен, что понял вашу мысль. В моем первом примере есть неявное преобразование. Кроме того, я думаю, что вы отвечаете на неправильный вопрос во второй части. Мне не интересно, как определить принтер, чтобы он соответствовал правильной подписи. Мне интересно, как применить ограничение ввода, используемое в аргументах формата, в более простом примере (см. Первый).
Возможный дубликат объяснение поведения функций высшего порядка и помеченных аргументов в OCaml