1

In OCaml while using the compiler, I wish to print the answers to the following 3 expressions :

map (fun s -> s^"to") ["tak";"tok";"tek"] ;; 

map (fun x -> x >= 0) [ 7 ; -13; -103; 79; 1230 ];; 

map List.hd [ [false;false;true] ; [false;true;true]; [true;false;true]];;

When I use the OCaml Top-Level interpreter, I get the right answers needed which are respectively :

> map (fun s -> s^"to") ["tak";"tok";"tek"] ;; 
> - : string list = ["takto"; "tokto"; "tekto"]

> map (fun x -> x >= 0) [ 7 ; -13; -103; 79; 1230 ];; 
> - : bool list = [true; false; false; true; true]

> map List.hd [ [false;false;true] ; [false;true;true]; [true;false;true] ];;
> - : bool list = [false; false; true]

How can I replicate this using the OCaml compiler ? How can I write the print instructions needed to get the job done ?

Nixtwan
  • 35
  • 6

2 Answers2

1

It's true, the OCaml toplevel (REPL) has a generalized printer that isn't available in compiled code.

If you're just getting started with OCaml I think it's best just to write your own printing functions by hand. This will let you concentrate on learning the basics of the language rather than the fancy ways of extending it.

Here for example is a function that writes out a list of strings to stdout:

let print_strings sl =
    let q s = "\"" ^ s ^ "\"" in
    Printf.printf "[ %s ]\n" (String.concat "; " (List.map q sl))

Strings are the easy case, of course, because they're already printable. But you can handle the other cases fairly similarly.

There is a way to print a boolean using Printf.printf "%b"

Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
1

It is nearly1 impossible as the OCaml compiler translates the program into a binary form and erases type information. In other words, after the program is compiled when it runs the runtime only sees machine integers and has no information about whether this integer shall be treated as a pointer to a string, a real integer, a user-defined data type, and so on.

In fact, this is true for many compiled languages, like C or C++. They also require the user to provide a specific function for printing their data types and specify the types when the printer is invoked.

In OCaml, we commonly print using the printf function from the Format module. This function is very similar to the same function in C/C++ (except that it is type-safe), e.g.,

open Format

let () = 
  printf "Hello, %s world\n%!" "cruel";
  printf "Hello, %d times!\n%!" 42

As you can see, the special format specifiers, like %s or %d specify the type of an argument. So %d expects one argument of type int, and %s expects one of string, there is also %c for char , %b for bool and so on. Besides, the %! specifier stands for flush, it will immediately output the information to the console device (otherwise it might be buffered).

There is also a generic %a specifier, which expects not one argument, but two – a function, which will tell how to print the argument, and the argument itself. It is used to print values of abstract types, hence the name %a. There is a convention, that modules that define abstract types also provide a function called pp which specifies how this value should be printed, e.g.,

let () = printf "Hello, abstract student %a\n%!" Student.pp s

Where the Student module might be defined as

struct Student : sig 
   type t 
   val create : string -> int -> t
   val pp : Format.formatter -> t -> unit
end = struct 
   type t = {name : string; cls : int}
   let create name cls  = {name; cls}
   let pp ppf {name; cls} = 
      Format.fprintf ppf "%s of %d" name cls
end

For modules provided by other libraries you can look for pp function as the generic printer. If such is not present, you can also try to use to_string together with the %s specifier.

The Format module (which is part of the OCaml standard library) comes with a few helpers, for example, there is a pp_print_list function that could be used to make printers for lists, e.g.,

let pp_bool ppf x = fprintf ppf "%b" x

let pp_bools ppf xs = 
   pp_print_list pp_bool ppf xs
   ~pp_sep:(fun ppf () -> fprintf ppf ", ");

and now we can print a list of booleans,

printf "(%a)\n" pp_bools [true; false; true]

will give us,

(true, false, true)

You may notice and even become annoyed by the fact, that there is no pp printer for Bool in the standard library. You're not alone! You may find, for example, that the fmt library (opam install fmt) makes printing much more fun. You may also use various deriving preprocessors that will derive printers for user-defined types, see the link at the end of the post. But this for advanced uses, for starters you have to master the Format library.


1) The true story is as always a bit more complicated. OCaml still preserves some information by employing value tagging, which enables projects such as genprintlib that provide generic printers that work for any objects even when the program is compiled to a native representation. It is quite a hacky project that relies on the inner and undocumented features of the runtime, so use it with care and for debugging only. See also this discussion

ivg
  • 34,431
  • 2
  • 35
  • 63