Types 使用带有可选参数的打印机以格式键入

Types 使用带有可选参数的打印机以格式键入,types,format,arguments,ocaml,optional,Types,Format,Arguments,Ocaml,Optional,我正面临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 mat

我正面临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. *)
当函数具有可选参数时,可以将其类型化为没有可选参数的函数

(** 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
这是编译器为在
fprintf
调用中使用
elt_打印机
而返回的内容:

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_打印机

    let f (elt : _ elt) =
      Format.printf
        "%a"
        (elt_printer : _ printer) elt
    
    编辑2: 对于带标签的参数,typer严格阻止类型转换,因为必须为参数提供特定的名称。这不是我问题中提出的问题

  • 是的,这是预期的,函数
    ?foo->bar->baz
    不能转换为
    bar->baz
    的函数。它只能在没有
    foo
    的情况下应用,这与隐式转换非常不同

  • 有两种解决方案

  • 首先,您可以“不应用”标签:
    f?print\u annot:None
    将通知打字机
    f
    的参数
    print\u annot
    应被视为不存在

    其次,这是我用于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
    

    我的问题的可能重复处理了具有可选参数的高阶函数的类似用法的两种不同行为之间的差异。这个帖子(虽然很有趣)没有提供一个明确的答案。谢谢你的回答,但我不确定你的观点是否理解。在我的第一个示例中,有一个隐式转换。另外,我认为你在第二部分回答了错误的问题。我不想知道如何定义打印机以匹配正确的签名。我想知道如何在一个更简单的示例(参见第一个示例)中应用格式参数中使用的类型限制。