krokodil
krokodil

Reputation: 1366

Wrapping up Format.formattter

I am trying to define a function msg which will allow printing debug messages using Format library with an option to control if they displayed or not via debug flag (set from a command line). Here is my naive first attempt:

let debug = ref false

let msg =
  let open Format in
  (if !debug then fprintf err_formatter else ifprintf err_formatter)

Unfortunately, this does not work, giving me the following error message:

Error: The type of this expression,
       ('_a, Format.formatter, unit) format -> '_a,
       contains type variables that cannot be generalized

What am I doing wrong? Thanks!

Upvotes: 1

Views: 39

Answers (1)

Jeffrey Scofield
Jeffrey Scofield

Reputation: 66818

This is the value restriction. You can solve it by "eta expansion":

let msg x =
    let open Format in
    if !debug then fprintf err_formatter x
    else ifprintf err_formatter x

Briefly stated, the value restriction avoids unsound behavior by prohibiting the generalization (treatment as fully polymorphic) of anything other than simple values. Your definition for msg is not a simple value. After eta expansion, the definition is a simple value (a lambda). You can read more here: Jacques Garrigue, Relaxing the Value Restriction.

The new code works for me:

# let debug = ref true
val debug : bool ref = {contents = true}

# let msg x =
    let open Format in
    if !debug then fprintf err_formatter x
    else ifprintf err_formatter x;;
val msg : ('a, Format.formatter, unit) format -> 'a = <fun>

# let open Format in
  msg "%d " 1; msg "%s" "red rose that I mean";
  pp_print_flush err_formatter ();;
1 red rose that I mean- : unit = ()
#

Upvotes: 1

Related Questions