自定义打印机到字符串

Custom printer to string

我定义了一个自定义的漂亮打印机,它接受一条消息,自定义它并打印它:

let mypp ppf msg =
  Format.fprintf ppf "Hello";
  Format.fprintf ppf msg

现在,我想用它来打印一个字符串,但因为我想多次使用它,所以我想把它放在一个函数中:

let myspp msg =
  let _ = mypp Format.str_formatter msg in
  Format.flush_str_formatter ()

但是写不出我想要的:

12 |   let s = myspp "Bleh %s" "world" in
               ^^^^^
Error: This function has type ('a, Format.formatter, unit) format -> string
       It is applied to too many arguments; maybe you forgot a `;'.

更糟糕的是,如果我删除参数:

let () =
  let s = myspp "Bleh %s" in
  Format.eprintf "---%s---@." s

结果:

---Hello: ---

格式化字符串消失了。

我知道我遗漏了一些东西,但找不到。我尝试使用 kfprintf 但没有取得好的结果。也许我需要改变我原来的功能?

需要注意的是,如果我不在函数中使用它,它会按预期工作:

let () = 
  mypp Format.str_formatter "Blah %s" "blih";
  Format.eprintf "---%s---@." (Format.flush_str_formatter ())

结果:

---Hello: Blah blih---

因为你想在提供所有格式参数后运行一些函数,唯一的选择是使用kfprintf:

let to_string msg =
  let b = Buffer.create 17 in
  let ppf = Format.formatter_of_buffer b in
  Format.fprintf ppf "Hello: ";
  Format.kfprintf (fun ppf ->
    Format.pp_print_flush ppf ();
    Buffer.contents b
  ) ppf msg

  let s = to_string "%d + %d = %d" 1 2 3

最好避免 Format.str_formatter,因为这样可以避免在程序中引入全局可变状态。

编辑:

如果重点是重用 mypp 函数,最简单的修复方法是向 mypp 添加一个延续参数:

let kmypp k ppf msg =
  Format.fprintf ppf "Hello";
  Format.kfprintf k ppf msg

let to_string msg =
  let b = Buffer.create 17 in
  let ppf = Format.formatter_of_buffer b in
  kmypp (fun ppf ->
    Format.pp_print_flush ppf ();
    Buffer.contents b
  ) ppf msg