带有可选参数的Printf错误

Lho*_*ooq 2 ocaml

假设我写了这个函数:

let f ?(x=0) fmt y = Format.fprintf fmt "%d" (x+y)
Run Code Online (Sandbox Code Playgroud)

它的类型是: ?x:int -> Format.formatter -> int -> unit

我可以指定x或不指定.

现在,让我们这样称呼它:

let () = Format.printf "%a@." f 0
Run Code Online (Sandbox Code Playgroud)

我有这个错误:

Error: This expression has type ?x:int -> Format.formatter -> int -> unit
       but an expression was expected of type Format.formatter -> 'a -> unit
Run Code Online (Sandbox Code Playgroud)

好吧,我不明白为什么这会是一个问题.参数是可选的,如果我不说它应该没问题,不是吗?(写作 Format.printf "%a" (f ~x:0) 0 很明显,但有可选参数的意义何在?)

我的意思是,如果我声明我的函数是这样的:

let f ?(x=0) () fmt y = Format.fprintf fmt "%d" (x+y)
Run Code Online (Sandbox Code Playgroud)

它的类型是:?x:int -> () -> Format.formatter -> int -> unit并且调用Format.printf "%a@." (f ()) 0将起作用.所以我猜可选参数不能成为函数的最后一个参数,但事实并非如此.

oct*_*ron 5

这个问题源于非常灵活的类型printf:('a, Format.formatter, unit) format -> 'a.当时,类型检查器推断出预期的类型fFormat.formatter -> int -> unit,应用可选参数为时已晚.在这种情况下,甚至可以帮助typechecker解决问题(但打破公国)

let pf fmt f = Format.printf fmt f
let () = pf "%a@." f 0 (* works *)
Run Code Online (Sandbox Code Playgroud)

请注意,这是一个非常普遍的问题,高阶函数在使用带标记或可选参数处理函数参数时会遇到一些困难.

  • 使用`()`参数,类型检查器可以推断出在检查`f()`时省略了可选参数,因此推断更加局部;而在 `printf` 应用程序中,可选参数的消除依赖于从应用程序上下文中流出的类型信息。 (2认同)