# Printing

OCaml has built-in printing functions for several of the built-in primitive types: print_char, print_int, print_string, and print_float. There's also a print_endline function, which is like print_string but also outputs a newline.

Let's look at the type of a couple of those functions:

# print_endline;;
- : string -> unit = <fun>

# print_string;;
- : string -> unit = <fun>


They both take a string as input and return a value of type unit, which we haven't seen before. There is only one value of this type, which is written () and is also pronounced "unit". So unit is like bool, except there is one fewer value of type unit than there is of bool. Unit is therefore used when you need to take an argument or return a value, but there's no interesting value to pass or return. Unit is often used when you're writing or using code that has side effects. Printing is an example of a side effect: it changes the world and can't be undone.

If you want to print one thing after another, you could sequence some print functions using nested let expressions:

let x = print_endline "THIS" in
let y = print_endline "IS" in
print_endline "3110"


But the boilerplate of all the let x = ... in above is annoying to have to write! We don't really care about giving names to the unit values returned by those printing functions. So there's a special syntax that can be used to chain together multiple functions who return unit. The expression e1; e2 first evaluates e1, which should evaluate to (), then discards that value, and evaluates e2. So we could rewrite the above code as:

print_endline "THIS";
print_endline "IS";
print_endline "3110"


And that is far more idiomatic code.

If e1 does not have type unit, then e1; e2 will give a warning, because you are discarding useful values. If that is truly your intent, you can call the built-in function ignore : 'a -> unit to convert any value to ():

# 3; 5;;
Warning 10: this expression should have type unit.
- : int = 5

# ignore 3; 5;;
- : int = 5