Я сталкиваюсь с интересным поведением типера 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
в первом примере?
Заранее спасибо.
EDIT:
Можно принудительно ввести elt_printer
без дополнительного аргумента, объяснив его тип.
let f (elt : _ elt) =
Format.printf
"%a"
(elt_printer : _ printer) elt
РЕДАКТИРОВАТЬ 2:
Для помеченных аргументов типизатор строго блокирует преобразования типов, поскольку аргументам должно быть указано конкретное имя. Это не проблема, поднятая в моем вопросе.