ocaml printf 函数:如果某些条件成立,则完全跳过格式化

gfx*_*onk 3 printf ocaml

(摘自ocaml:在对象的方法中公开 printf 函数,因此可以独立回答)

我有以下(简化的)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
Run Code Online (Sandbox Code Playgroud)

logf 函数可以与 printf 格式一起使用,如下所示:

logf "func" Warn "testing with string: %s and int: %d" "str" 42;
Run Code Online (Sandbox Code Playgroud)

有没有什么方法可以实现仅在实际需要时格式化参数的典型日志记录行为?即类似:

let logf name lvl <args> =
    if (ord lvl) >= !current_level then
        Printf.printf <args>
Run Code Online (Sandbox Code Playgroud)

我想这是因为只有编译器知道格式表达式中有多少个参数,而且我猜 ocaml 中没有诸如 varargs 之类的东西?因此,您无法定义printf 函数的完整主体,只能使用柯里化并让编译器神奇地解决它。有什么办法可以实现我想要的吗?也许与mkprintf

gsg*_*gsg 5

专门提供诸如此类的延续函数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
Run Code Online (Sandbox Code Playgroud)