不直观的空格式化字符串

时间:2016-02-04 13:24:20

标签: format ocaml

我想在基于格式的日志记录工具中添加一个监听器机制,最后我的程序由OCaml输入并编译,但格式化的字符串刚刚消失,我不明白究竟为什么会发生这种情况(当格式化程序返回unit时它们应该返回其他内容时,它们会相关,但我希望程序在这种情况下不要进行类型检查)。

这来自一个真实的用例;然而,它的简化可能导致一个有点人为的程序。

基本需要是:设计一个类似Format.printf的函数(具有可变参数),该函数易于使用,但也允许通知其他格式化程序(例如复制其输出)。

我已经被告知由于输入限制而无法实现这一点,事实上如果我进一步简化下面的示例,我确实会输入错误,但由于某种原因,下面的程序会进行类型检查但不会产生预期的结果。

open Format

let observers : formatter list ref = ref []
let add_observer o : unit =
  observers := o :: !observers

let print_to_fmt (fmt: formatter) (text: ('a, formatter, unit) format) : unit =
  Format.fprintf fmt "<";
  Format.fprintf fmt text;
  Format.fprintf fmt ">@."

let notify text : unit =
  List.iter (fun fmt ->
      Format.printf "MESSAGE: {";
      Format.printf text;
      Format.printf "}@.";
      print_to_fmt fmt text
    ) !observers

let buffer = ref ""
let append text _ _ = buffer := text

let print text =
  let fmt = Format.make_formatter append (fun () -> ()) in
  Format.kfprintf (fun f -> ()) fmt text

let log text =
  notify text;
  print text

let () =
  add_observer (Format.err_formatter);
  log "this works";
  log "this does not %d" 42;
  log "this also works"

有关如何(1)更改程序以显示this does not 42的任何帮助,或(2)解释为什么程序类型检查它似乎不应该被解释,将非常感激。

1 个答案:

答案 0 :(得分:1)

你试图用格式化程序做一个非常奇怪的魔法,我会将其归类为滥用,老实说。 Formatter是一个格式化的通道,而不是数据,因此它们会强加所有通道问题,例如突然消失的非持久性数据。

如果您想要一个日志功能,它将在已注册的格式化程序之间分配数据,那么以下内容将起作用:

open Format

let observers : formatter list ref = ref []
let add_observer o : unit =
  observers := o :: !observers

let notify (text : string) : unit =
  List.iter (fun fmt ->
      fprintf fmt "MESSAGE: {%s}@." text) !observers

let log text = ksprintf notify text

let () =
  add_observer Format.err_formatter;
  log "this works";
  log "this does not %d" 42;
  log "this also works"

将撕掉以下输出:

MESSAGE: {this works}
MESSAGE: {this does not 42}
MESSAGE: {this also works}