9

If I execute the following in OCaml's toplevel:

#require "num";;
open Ratio;;

ratio_of_int 2;;

The output is:

- : Ratio.ratio = <ratio 2/1>

How's a formatting like this possible? The sources tell me that Ratio.ratio is a record. So the output should be more akin to

{numerator = <big_int 2>; denominator = <big_int 1>; normalized = true}

I tried see if ratio output is somehow hardcoded in toplevel, but this search was fruitless. Being new to OCaml, I must ask if I'm missing something important? In a language that has overloaded stringification funcs this wouldn't be strange, but in OCaml's case I find this behavior quite out of place.

Rutherford
  • 103
  • 5

2 Answers2

6

Findlib has a pretty printer specifically for the ratio module. Instead of printing out <abstr> (the interface doesn't expose the record), it prints out what you saw. If you want to check it out, look at findlib/num_top_printers.ml:

let ratio_printer fmt v =
  Format.fprintf fmt "<ratio %s>" (Ratio.string_of_ratio v)
Niki Yoshiuchi
  • 16,883
  • 1
  • 35
  • 44
  • Yeah, I just figured this out while pondering your (now deleted) question. Thanks for your help! – Rutherford Dec 15 '10 at 19:40
  • Yeah, I was confused at first because I didn't have findlib installed on my computer at work. I knew it was due to a pretty printer but didn't know where the pretty printer was located at until I realized that it was findlib. – Niki Yoshiuchi Dec 15 '10 at 19:45
  • 2
    Seems like using [custom pretty printers in toplevel](http://caml.inria.fr/pub/docs/manual-ocaml/manual023.html#toc90) is quite easy. – Rutherford Dec 15 '10 at 19:51
  • Yet, I think using pretty printers is just a hack around the frustrating limitation in OCaml that functions can't be overloaded. – Rutherford Dec 15 '10 at 20:14
  • In case the URL changes again, documentation for [custom pretty printers in the toplevel](https://v2.ocaml.org/releases/5.0/htmlman/toplevel.html#s%3Atoplevel-directives) is found in OCaml Manual 14.2 – mndrix Jan 02 '23 at 22:57
5

The toplevel has a directive #install_printer, that takes a function to print any type.

For example, you can redefine how to print integers like this:

let print_integer ppf n = Format.fprintf ppf "Integer(%d)" n
#install_printer print_integer

#install_printer chooses printers depending on the type of the function given as argument (here, Format.formatter -> int -> unit).

Fabrice Le Fessant
  • 4,222
  • 23
  • 36