我想在基于格式的日志记录工具中添加一个监听器机制,最后我的程序由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)解释为什么程序类型检查它似乎不应该被解释,将非常感激。
答案 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}