问题
I have the following (simplified) ocaml code, for a logger:
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
The logf function can be used with a printf format, as in:
logf "func" Warn "testing with string: %s and int: %d" "str" 42;
1) How can I wrap this up in an object, so that name is bound? I tried:
class logger (name:string) =
object (self)
method logf lvl = logf name lvl
end
(my real logger has a bunch more methods, so it's not as pointless as it looks here. Also, the name gets printed depending on the formatter, even though I haven't included that code here)
But I get:
The method logf has type
log_level -> ('a, unit, string, unit) format4 -> 'a
where 'a is unbound
This seems reasonable, knowing what I know about the format4 type - it doesn't know what inputs it's going to be receiving. But how come the free function above works just fine? My guess is that the compiler is able to somehow specialize this abstract / unbound type wherever it's used in the case of the function, but not in the case of the class?
Edit: I moved part (2) to ocaml printf function: skip formatting entirely if some condition holds so it can be answered independently
回答1:
For (1), you can use this:
class logger (name: string) =
object (self)
method logf : 'a. log_level -> ('a, unit, string, unit) format4 -> 'a =
fun lvl -> logf name lvl
end
The extra syntax creates a so-called polymorphic method.
Here's a session that shows it working:
$ 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 = ()
#
For (2), I think things already work as you would like. No formatting will happen if the level is too low.
来源:https://stackoverflow.com/questions/20411450/ocaml-exposing-a-printf-function-in-an-objects-method