Why doesn't this short OCaml snippet with Printf.printf work?

ocaml, printf

Solution

There is a kind of "overloading" of the meaning of string literals in OCaml. At compile time, they can either be interpreted as a string, or as a format (which are completely different things in the type system), depending on what the type-checker thinks. If it decides that it should be a format, then the format string is parsed directly at compile-time (that is why it is able to type-check the arguments to printf at compile time). (Unlike C, which parses the string at runtime.) However, there is no simple way to convert from a string into a format at runtime. So when you see Printf.printf "2.5", the "2.5" is actually not a string, but as a special format type that was parsed at compile-time. That is why you cannot substitute a string for it.

On an unrelated note, if you just want to print a string, you might want to use `print_string` (or `print_endline` if you want a newline).

Problem

I'm a OCaml newbie. I'm playing around with "hello world" type snippets and came across this situation. Here's a session with the interpreter with some extra comments: ``` # let average a b = (a +. b) /. 2.;; val average : float -> float -> float = <fun> # average 1. 4.;; - : float = 2.5 # string_of_float (average 1. 4.);; - : string = "2.5" (* this fails...*) # let _ = Printf.printf (string_of_float (average 1. 4.));; Error: This expression has type string but an expression was expected of type ('a, out_channel, unit) format = ('a, out_channel, unit, unit, unit, unit) format6 (* yet this works *) # "hello!";; - : string = "hello!" # let _ = Printf.printf "hello!";; hello!- : unit = () (* another failed attempt *) # let s = string_of_float (average 1. 4.);; val s : string = "2.5" # s;; - : string = "2.5" # let _ = Printf.printf s;; Error: This expression has type string but an expression was expected of type ('a, out_channel, unit) format = ('a, out_channel, unit, unit, unit, unit) format6 (* and this also works?? *) # let _ = Printf.printf "2.5";; 2.5- : unit = () ``` So here's the situation. `string_of_float (average 1. 4.)` returns a string, just as `"hello!"` does. When I give `"hello!"` into `Printf.printf`, it works as expected. When I give `string_of_float (average 1. 4.)` to `Printf.printf` it fails and tells me it expected didn't expect a string but that other weird type. But why do `"hello!"` and `"2.5"` work then? What's going on?

Original source