Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

printf

ocaml

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?

like image 755
dimatura Avatar asked Mar 05 '10 18:03

dimatura


2 Answers

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).

like image 139
newacct Avatar answered Nov 20 '22 10:11

newacct


Printf.printf "%s" anyStringExpr

will work. The first argument to printf is somewhat magical. (Others will fill in the details.)

like image 44
Brian Avatar answered Nov 20 '22 10:11

Brian