对于记录器,我有以下(简化的)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;
1)如何将其包装在一个对象中,以便绑定name
?我试过了:
class logger (name:string) =
object (self)
method logf lvl = logf name lvl
end
(我的真正的记录器有更多的方法,所以它不像它在这里看起来那么毫无意义。而且,name
根据格式化程序打印,即使我没有在此处包含该代码)< / p>
但我明白了:
The method logf has type
log_level -> ('a, unit, string, unit) format4 -> 'a
where 'a is unbound
这似乎是合理的,知道我对format4类型的了解 - 它不知道它将接收什么输入。但是为什么上面的免费功能怎么样呢?我的猜测是编译器能够以某种方式专门化这个抽象/未绑定类型,无论它在函数的情况下使用它,但不是在类的情况下?
编辑:我将第(2)部分移至ocaml printf function: skip formatting entirely if some condition holds,以便可以独立回答
答案 0 :(得分:2)
对于(1),您可以使用:
class logger (name: string) =
object (self)
method logf : 'a. log_level -> ('a, unit, string, unit) format4 -> 'a =
fun lvl -> logf name lvl
end
额外的语法创建了一种所谓的多态方法。
这是一个显示它有效的会话:
$ ocaml
OCaml version 4.00.1
# #use "opf.ml";;
type log_level = Error | Warn | Info
val ord : log_level -> int = <fun>
val current_level : int ref = {contents = 40}
val logf : 'a -> log_level -> ('b, unit, string, unit) format4 -> 'b = <fun>
class logger :
string ->
object
method logf : log_level -> ('a, unit, string, unit) format4 -> 'a
end
# let l = new logger "name";;
val l : logger = <obj>
# l#logf Warn "Testing with %d %s" 88 "maybe";;
Testing with 88 maybe
- : unit = ()
#
对于(2),我认为事情已经按照您的意愿运作了。如果级别太低,则不会进行格式化。