(摘自ocaml: exposing a printf function in an object's method,因此可以单独回答)
对于记录器,我有以下(简化的)ocaml代码:
type log_level =
| Error
| Warn
| Info
let ord lvl =
match lvl with
| Error -> 50
| Warn -> 40
| Info -> 30
let current_level = ref (ord Warn)
let logf name lvl =
let do_log str =
if (ord lvl) >= !current_level then
print_endline str
in
Printf.ksprintf do_log
logf函数可以与printf格式一起使用,如:
logf "func" Warn "testing with string: %s and int: %d" "str" 42;
有没有办法在实际需要时只实现格式化参数的典型日志记录行为?,例如:
let logf name lvl <args> =
if (ord lvl) >= !current_level then
Printf.printf <args>
我在想它是因为只有编译器才知道格式表达式中会有多少个参数,我想在ocaml中没有varargs这样的东西?因此,您无法定义printf函数的完整正文,您只能使用currying并让编译器魔术解决它。有没有办法实现我想要的?也许是mkprintf
?
答案 0 :(得分:4)
Printf.kfprintf
等延续函数专门用于允许这样的格式包装。它看起来像这样:
open Printf
type log_level = Error | Warn | Info
let ord = function Error -> 50 | Warn -> 40 | Info -> 30
let string_of_lvl = function
| Error -> "error"
| Warn -> "warn"
| Info -> "info"
let current_level = ref (ord Warn)
let printf_with_info name lvl =
kfprintf fprintf stdout "[<%s>] <%s>: " name (string_of_lvl lvl)
let logf name lvl =
if ord lvl >= !current_level then match lvl with
| Error | Warn -> printf
| Info -> printf_with_info name lvl
else
ifprintf stdout
答案 1 :(得分:1)
这似乎让我有了一些方法:
let logf name lvl =
if (ord lvl) >= !current_level then
Printf.fprintf stdout
else
Printf.ifprintf stdout
我很惊讶,因为我认为这可能意味着!current_level会过早评估(在模块加载时或其他什么时候)。但是在运行时更改current_level似乎可以正常工作。我想currying并不像haskell一样纯净(考虑到上面的杂质,这是有道理的。)。)。
但它限制我使用fprintf
系列。我更喜欢使用ksprintf
,因为我还想要一个格式化程序,它(取决于日志级别)可能会添加如下信息:
`[<name>] <level>: <message>`
也许我可以通过连接格式来实现这一点(使用^^
),但我不知道如何。
答案 2 :(得分:0)
无论你做什么,调用任何Printf.*printf
函数都会在运行时解析格式字符串。这可能会在4.02中发生变化。或者您可以使用一些语法扩展来进行条件打印。