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

时间:2013-12-06 00:28:27

标签: printf ocaml

(摘自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

3 个答案:

答案 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中发生变化。或者您可以使用一些语法扩展来进行条件打印。