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

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?

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

Printf.printf "%s" anyStringExpr
will work. The first argument to printf is somewhat magical. (Others will fill in the details.)

Related

Printf arguments in OCaml

In OCaml, I obtain an error I do not understand when passing arguments which should work to Printf.printf. It is probably because I do not understand that function completely, but I cannot pin down what does not work.
First, I define a function (used for logging):
utop # let log verbosity level str =
if level <= verbosity then (
Printf.printf "\nLevel %i: " level;
Printf.printf str);;
val log : int -> int -> (unit, out_channel, unit) format -> unit = <fun>
All seems well, but then I obtain this:
utop # log 0 0 "%i" 0;;
Error: This function has type
int -> int -> (unit, out_channel, unit) format -> unit
It is applied to too many arguments; maybe you forgot a `;'.
although the following works:
utop # Printf.printf;;
- : ('a, out_channel, unit) format -> 'a = <fun>
utop # Printf.printf "%i" 0;;
0- : unit = ()
So, how can I define a function which does what log intends to do ?
Edit: Indeed, log 0 0 "%i" 0;; looks like too many arguments (4 instead of 3), but so does Printf.printf "%i" 0;; (2 instead of 1), and it works. With partial application, this gives this:
utop # Printf.printf "%i";;
- : int -> unit = <fun>
utop # log 0 0 "%i";;
Error: This expression has type (unit, unit) CamlinternalFormatBasics.precision
but an expression was expected of type
(unit, int -> 'a) CamlinternalFormatBasics.precision
Type unit is not compatible with type int -> 'a
The printf-like functions are variadic, in the sense that they accept a variable number of arguments. It is not really specific to printf and the family, you can define your own variadic functions in OCaml, this is fully supported by the type system. The only magic of printf is that the compiler translates a string literal, e.g., "foo %d to a value of type format.
Now, let's look at the type of the printf function,
('a, out_channel, unit) format -> 'a
Notice that it returns 'a which is a type variable. Since 'a could be anything it could be also a function. The ('a, out_channel, unit) format is the type of the format string that defines the type of function that is generated by this format string. It is important to understand though, that despite that "foo %d" looks like a string, in fact, it is a special built-in value of type _ format, which has a literal that looks like a string (though not all valid strings are valid literals for the _ format type.
Just to demonstrate that the first argument of printf is not a string, let's try the following,
# Printf.printf ("foo " ^ "%d");;
Line 1, characters 14-29:
1 | Printf.printf ("foo " ^ "%d");;
^^^^^^^^^^^^^^^
Error: This expression has type string but an expression was expected of type
('a, out_channel, unit) format
Now, when we know that printf is not a typical function, let's define a printf-like function ourselves. For that we need to use the kprintf-family of functions, e.g.,
# #show Printf.ksprintf;;
val ksprintf : (string -> 'd) -> ('a, unit, string, 'd) format4 -> 'a
This function takes the function which receives the resulting string which we can log, for example,
# let log fmt = Printf.ksprintf (fun s -> print_endline ("log> "^s)) fmt;;
val log : ('a, unit, string, unit) format4 -> 'a = <fun>
# log "foo";;
log> foo
- : unit = ()
This resulting function looks more like sprintf, i.e., it will play nicely with pretty-printing function that work with string as their output devices (this is a different topic). You may find it more easier to define your logging functions, using either Printf.kfprintf or, much better, using Format.kasprintf or Format.kfprintf. The latter two functions have the following types,
val kasprintf : (string -> 'a) -> ('b, formatter, unit, 'a) format4 -> 'b
val kfprintf : (formatter -> 'a) -> formatter ->
('b, formatter, unit, 'a) format4 -> 'b
But the type of format works with the formatter type (which is an abstraction of the output device) that is the type that the pretty printers (conventionally named pp) are accepting. So the log function defined using the Format module will play better with the existing libraries.
So, using Format.kasprintf we can define your log function as,
# let log verbosity level =
Format.kasprintf (fun msg ->
if level <= verbosity then
Format.printf "Level %d: %s#\n%!" level msg);;
val log : int -> int -> ('a, Format.formatter, unit, unit) format4 -> 'a = <fun>
And here is how it could be used,
# log 0 0 "Hello, %s, %d times" "world" 3;;
Level 0: Hello, world, 3 times
- : unit = ()

The signature for this packaged module couldn't be inferred in recursive function

I'm still trying to figure out how to split code when using mirage and it's myriad of first class modules.
I've put everything I need in a big ugly Context module, to avoid having to pass ten modules to all my functions, one is pain enough.
I have a function to receive commands over tcp :
let recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan = ...
After hours of trial and errors, I figured out that I needed to add (type a) and the "explicit" type chan = a to make it work. Looks ugly, but it compiles.
But if I want to make that function recursive :
let rec recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan =
Ctx.readMsg chan >>= fun res ->
... more stuff ...
|> OtherModule.getStorageForId (module Ctx)
... more stuff ...
recvCmds (module Ctx) nodeid chan
I pass the module twice, the first time no problem but
I get an error on the recursion line :
The signature for this packaged module couldn't be inferred.
and if I try to specify the signature I get
This expression has type a but an expression was expected of type 'a
The type constructor a would escape its scope
And it seems like I can't use the whole (type chan = a) thing.
If someone could explain what is going on, and ideally a way to work around it, it'd be great.
I could just use a while of course, but I'd rather finally understand these damn modules. Thanks !
The pratical answer is that recursive functions should universally quantify their locally abstract types with let rec f: type a. .... = fun ... .
More precisely, your example can be simplified to
module type T = sig type t end
let rec f (type a) (m: (module T with type t = a)) = f m
which yield the same error as yours:
Error: This expression has type (module T with type t = a)
but an expression was expected of type 'a
The type constructor a would escape its scope
This error can be fixed with an explicit forall quantification: this can be done with
the short-hand notation (for universally quantified locally abstract type):
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m
The reason behind this behavior is that locally abstract type should not escape
the scope of the function that introduced them. For instance, this code
let ext_store = ref None
let store x = ext_store := Some x
let f (type a) (x:a) = store x
should visibly fail because it tries to store a value of type a, which is a non-sensical type outside of the body of f.
By consequence, values with a locally abstract type can only be used by polymorphic function. For instance, this example
let id x = x
let f (x:a) : a = id x
is fine because id x works for any x.
The problem with a function like
let rec f (type a) (m: (module T with type t = a)) = f m
is then that the type of f is not yet generalized inside its body, because type generalization in ML happens at let definition. The fix is therefore to explicitly tell to the compiler that f is polymorphic in its argument:
let rec f: 'a. (module T with type t = 'a) -> 'never =
fun (type a) (m:(module T with type t = a)) -> f m
Here, 'a. ... is an universal quantification that should read forall 'a. ....
This first line tells to the compiler that the function f is polymorphic in its first argument, whereas the second line explicitly introduces the locally abstract type a to refine the packed module type. Splitting these two declarations is quite verbose, thus the shorthand notation combines both:
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m

Print elements in list in OCaml

I want to write a tail recursive function to print elements in a string list in separate lines like this:
# printlist ["a";"b";"c"];;
a
b
c
- : unit = ()
# printlist ["hello";"thanks"];;
hello
thanks
- : unit = ()
I was able to get it to work using print_endline with no problem:
let rec printlist strlist =
match strlist with
| [] -> print_endline ""
| hd::[] -> print_endline hd
| hd :: tl -> print_endline hd ; printlist tl;;
However, as soon as I switch to printf, it doesn't work anymore. What's wrong with my printf version?
let rec printlist strlist =
match strlist with
| [] -> printf ""
| hd::[] -> printf hd
| hd :: tl -> printf "%s\n" hd ; printlist tl;;
Error: This expression has type
(unit, out_channel, unit) format =
(unit, out_channel, unit, unit, unit, unit)
CamlinternalFormatBasics.format6
but an expression was expected of type string
In essence, you're trying to use printf without a format. The first argument of printf has to be a constant string. So you should have this:
printf "%s" hd
rather than this:
printf hd
To see why this is required, imagine what would happen if some of the strings in your input contained percent characters. Things would get out of control (type-wise) quite quickly.
In addition to Jeffrey's answer, I would suggest you use the standard library more in order to write more concise code.
List.iter, for example, calls a given function on all the elements of the list:
let print_list l = List.iter (fun e -> Printf.printf "%s\n" e) l
Using partial application smartly, you can make this line even shorter and more readable:
let print_list = List.iter (Printf.printf "%s\n")
The only difference with your function is the newline after the last element.
On the other hand, instead of printing elements one after another, a more functional and idiomatic approach would be to build the whole string first, and then print it.
Lucky you, the standard library got you covered. String.concat joins the elements in a string list together in one big string. You can also specify a string to use as a separator, and you don't have to worry about the newline after the last element.
let print_list l = print_string (String.concat "\n" l)

How to Compare Types for Equality?

I attempted to compare a String and String, expecting True.
Idris> String == String
Can't find implementation for Eq Type
Then I expected False when comparing a String to a Bool.
Idris> String /= Bool
Can't find implementation for Eq Type
Am I missing an import?
You can't as it would break parametricity, which we have in Idris. We can't pattern match on types. But this would be necessary to write the Eq implementation, for example:
{- Doesn't work!
eqNat : Type -> Bool
eqNat Nat = True
eqNat _ = False -}
Also, if one could pattern match on types, they would be needed in the run-time. Right now types get erased when compiling.
Just to add some simple examples to the above: types can't be pattern matched on, but there's a two parameter type constructor for propositional equality, described in the documentation section on Theorem Proving. Notice that the only constructor, Refl, makes only values of type (=) x x, where both type parameters are the same. (this is ≡ in Agda)
So this will typecheck:
twoPlusTwoEqFour : 2 + 2 = 4
twoPlusTwoEqFour = Refl
so will this:
stringEqString : String = String
stringEqString = Refl
but not this:
stringEqInt : String = Int
stringEqInt = Refl
-- type error: Type mismatch between String and Int
and this needs extra work to prove, because addition is defined by recursion on the left argument, and n + 0 can't be reduced further:
proof : n = n + 0

SML converting a string to an int with error catching

So what I want to do is to convert a string into an int and do some error catching on it. I would also like to know where I would put what I want it to do after it fails if it does.
I know how to convert, but I am not sure how to catch it and where the code will jump to after the error
I believe the method for converting it Int.fromString(x)
Thank you.
SML has two approaches to error handling. One, based on raise to raise errors and handle to catch the error, is somewhat similar to how error handling works in languages like Python or Java. It is effective, but the resulting code tends to lose some of its functional flavor. The other method is based on the notion of options. Since the return type of Int.fromString is
string -> int option
it makes the most sense to use the option-based approach.
An int option is either SOME n, where n is and integer, or it is NONE. The function Int.fromString returns the latter if it fails in its attempt to convert the string to an integer. The function which calls Int.fromString can explicitly test for NONE and use the valOf to extract the value in the case that the return value is of the form SOME n. Alternatively, and somewhat more idiomatically, you can use pattern matching in a case expression. Here is a toy example:
fun squareString s =
case Int.fromString(s) of
SOME n => Int.toString (n * n) |
NONE => s ^ " isn't an integer";
This function has type string -> string. Typical output:
- squareString "4";
val it = "16" : string
- squareString "Bob";
val it = "Bob isn't an integer" : string
Note that the clause which starts NONE => is basically an error handler. If the function that you are defining isn't able to handle such errors, it could pass the buck. For example:
fun squareString s =
case Int.fromString(s) of
SOME n => SOME (Int.toString (n * n))|
NONE => NONE;
This has type string -> string option with output now looking like:
- squareString "4";
val it = SOME "16" : string option
- squareString "Bob";
val it = NONE : string option
This would make it the responsibility of the caller to figure out what to do with the option.
The approach to error handling that John explains is elaborated in the StackOverflow question 'Unpacking' the data in an SML DataType without a case statement. The use-case there is a bit different, since it also involves syntax trees, but the same convenience applies for smaller cases:
fun squareString s = Int.fromString s >>= (fn i => SOME (i*i))
Assuming you defined the >>= operator as:
infix 3 >>=
fun NONE >>= _ = NONE
| (SOME a) >>= f = f a
The drawback of using 'a option for error handling is that you have to take into account, every single time you use a function that has this return type, whether it errored. This is not unreasonable. It's like mandatory null-checking. But it comes at the cost of not being able to easily compose your functions (using e.g. the o operator) and a lot of nested case-ofs:
fun inputSqrt s =
case TextIO.inputLine TextIO.stdIn of
NONE => NONE
| SOME s => case Real.fromString s of
NONE => NONE
| SOME x => SOME (Math.sqrt x) handle Domain => NONE
A workaround is that you can build this constant error handling into your function composition operator, as long as all your functions share the same way of expressing errors, e.g. using 'a option:
fun safeSqrt x = SOME (Math.sqrt x) handle Domain => NONE
fun inputSqrt () =
TextIO.inputLine TextIO.stdIn >>=
(fn s => Real.fromString s >>=
(fn x => safeSqrt x))
Or even shorter by applying Eta conversion:
fun inputSqrt () = TextIO.inputLine TextIO.stdIn >>= Real.fromString >>= safeSqrt
This function could fail either because of a lack of input, or because the input didn't convert to a real, or because it was negative. Naturally, this error handling isn't smart enough to say what the error was, so you might want to extend your functions from using an 'a option to using an ('a, 'b) either:
datatype ('a, 'b) either = Left of 'a | Right of 'b
infix 3 >>=
fun (Left msg) >>= _ = Left msg
| (Right a) >>= f = f a
fun try (SOME x) _ = Right x
| try NONE msg = Left msg
fun inputLine () =
try (TextIO.inputLine TextIO.stdIn) "Could not read from stdIn."
fun realFromString s =
try (Real.fromString s) "Could not derive real from string."
fun safeSqrt x =
try (SOME (Math.sqrt x) handle Domain => NONE) "Square root of negative number"
fun inputSqrt () =
inputLine () >>= realFromString >>= safeSqrt
And trying this out:
- ​inputSqrt ();
​9
> val it = Right 3.0 : (string, real) either
- ​inputSqrt ();
​~42
> val it = Left "Square root of negative number" : (string, real) either
- ​inputSqrt ();
Hello
> val it = Left "Could not derive real from string." : (string, real) either
- (TextIO.closeIn TextIO.stdIn; inputSqrt ());
> val it = Left "Could not read from stdIn." : (string, real) either