The problem occurs much more widely than just with the ^
operator. Basically, the OCaml compiler needs to know that your format string is a literal string, and the literal string needs to be known at compile time. Or else, OCaml cannot cast your string at compile time to this BLAHBLAH format6
type. The Printf
module works correctly only with format strings that are completely known at compile time, or with format strings that are already cast to the BLAHBLAH format
type.
Generally you can solve this problem by using the ^^
operator and by explicitly casting all literal strings to the BLAHBLAH format
type before using those strings in your code.
Here is another example:
# Printf.sprintf (if true then "%d" else "%d ") 2;;
Error: This expression has type string but an expression was expected of type
('a -> 'b, unit, string) format =
('a -> 'b, unit, string, string, string, string) format6
(* define a type abbreviation for brevity *)
# type ('a,'b) fformat = ('a ->'b, unit, string) format;;
type ('a, 'b) fformat = ('a -> 'b, unit, string) format
# Printf.sprintf (if true then ("%d":('a,'b)fformat) else ("%d ":('a,'b)fformat)) 2;;
- : string = "2"
The OCaml system cannot recognize that if ... then "a" else "b"
can be cast to BLAHBLAH format
. If you cast each literal string yourself to BLAHBLAH format
, then everything works. (Note: it does not work if you try to cast the entire if/then/else
to BLAHBLAH format
, since OCaml cannot verify that your string is a literal.)
The origin of the problem is the requirement of type safety: OCaml requires that there is an argument of the correct type for every %d
and %s
etc., and guarantees this at compile time. You cannot guarantee type safety with Printf
unless the entire format string is known at compile time. Therefore, it is impossible to use Printf
with a format string computed via a complicated algorithm, e.g., by selecting %s
and %d
at random.
When we use if/then/else
to compute the format string, then OCaml things, oh gee, this is a complicated algorithm, and it is hopeless to verify type safety at compile time. The ^^
operator knows about BLAHBLAH format
types and produces the correct result when concatenating format strings. But if/then/else
does not know about BLAHBLAH format
, and there is no built-in alternative to if/then/else
(but I guess you could define such a thing youself).