The OCaml repl ("toplevel") has rich printing for any types, user-defined or otherwise. Is it possible to access this functionality outside the toplevel, rather than having to write an entirely custom set of value printers for one's own entire set of types?
The pretty-printing facility is part of the toplevel library. You'll find the source in toplevel/genprintval.ml
. It's understandable, considering that it needs type information: you can't just throw any value at it, the choice of pretty-printer is based on the type.
If you want to use this code in your program, you'll need to link with the toplevel library (toplevellib.cma
) or compile in genprintval
(which means bringing in enough bits of the type checker to analyse the type, it can get pretty big).
There is a similar facility (but not sharing the code, I think) in the debugger (debugger/printval.ml
and debugger/loadprinter.ml
).
There are third-party libraries that you can directly link against and that provide pretty-printing facilities. Extlib's Std.dump
provides a very crude facility (not based on the type). Deriving by Jeremy Yallop and Jake Donham is another approach. This Caml Weekly News item offers more suggestions.
Extlib.Std.dump
and BatPervasives.dump
, mentioned by @newacct, are the same function: Extlib.Std.dump == BatPervasives.dump;;
=> bool = true
. –
Eolithic The OCaml Batteries Included library contains the dump
function in its BatPervasives module . It converts any value to a string and returns it. You can see its source code here. The output will not be identical to the toplevel, because some information is lost at runtime, e.g. abstract data type constructors will become integers.
No. As of OCaml 4.06, the compiler doesn't make type information available at runtime. It is therefore not possible to have standalone programs that nicely print any OCaml data without some compromises. The two main avenues are:
- Some form of preprocessing which derives printers from type definitions. Today, the best approach might be the show plugin of ppx-deriving. This requires annotating each type definition.
- Relying only on the runtime representation of values. This requires no effort from the programmer and works out-of-the-box on data produced by external libraries. However it doesn't show things like record field names or any other information that was lost during compilation. An instance of this approach is detailed below.
The function Dum.to_stdout
from the dum package will take any OCaml value, including cyclic ones, and print their physical representation in a human-readable form given the data available at runtime only.
Simple things give more or less what one would expect:
# Dum.to_stdout ("Hello", 42, Some `Thing, [1;2;3]);;
("Hello" 42 (582416334) [ 1 2 3 ])
Cyclic—and in general, shared—values are shown using labels and references. This is a circular list:
# let rec cyc = 1 :: 2 :: cyc;;
# Dum.to_stdout cyc;;
#0: (1 (2 #0))
We can also look into the runtime representation of functions, modules and other things. For example, the Filename
module can be inspected as follows:
# module type Filename = module type of Filename;;
# Dum.to_stdout (module Filename : Filename);;
(
#0: "."
".."
#1: "/"
#2: closure (#1 #3: closure ())
#4: closure ()
closure (#4)
closure ()
closure ()
closure (#5: closure (#3))
closure (#5)
closure (#5)
closure (closure () #3 #0)
closure (closure () #3 #0)
closure (#6: closure (#2 <lazy>) #7: (#8))
closure (#6 #7)
closure (#7)
closure (#7)
#8: "/tmp"
closure (closure () "'\\''")
)
opam install dum
–
Fester I know you want it outside of top level but I think it's worth mentioning how to do it in top level so that ppl looking for printing in anyway (since it seems outside top level is not trivial):
- load your file in top level
utop
#use "datatypes.ml";;
- then "call" the variable inside top level:
utop # let nada = Nothing;;
utop # nada;;
- : foo = Nothing
ref: https://discuss.ocaml.org/t/how-does-one-print-any-type/4362/16?u=brando90
#use "file.ml";;
and then call the variable var;;
in toplevel. –
Danelledanete © 2022 - 2024 — McMap. All rights reserved.
#use "file.ml";;
and then call the variablevar;;
in toplevel. – Danelledanete