ocaml: exposing a printf function in an object's method

我只是一个虾纸丫 提交于 2019-12-08 06:26:05

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!