I can't use print_endline
because it requires a string, and I don't (think) I have any way to convert my very simple user-defined datatypes to strings. How can I check the values of variables of these datatypes?
In many cases, it's not hard to write your own string_of_ conversion routine. That's a simple alternative that doesn't require any extra libraries or non-standard OCaml extensions. For the courses I teach that use OCaml, this is often the simplest mechanism for students.
(It would be nice if there were support for a generic conversion to strings though; perhaps the OCaml deriving stuff will catch on.)
There's nothing in the base language that does this for you. There is a project named OCaml Deriving (named after a feature of Haskell) that can automatically derive print functions from type declarations. I haven't used it, but it sounds excellent.
http://code.google.com/p/deriving/
Once you have a function for printing your type (derived or not), you can install it in the ocaml top-level. This can be handy, as the built-in top-level printing sometimes doesn't do quite what you want. To do this, use the #install-printer
directive, described in Chapter 9 of the OCaml Manual.
There are third-party library functions like dump
in OCaml Batteries Included or OCaml Extlib, that will generically convert any value to a string using all the runtime information it can get. But this won't be able to recover all information; for example, constructor names are lost and become just integers, so it will not look exactly the way you want. You will basically have to write your own conversion functions, or use some tool that will write them for you.
Along the lines of previous answers, ppx_sexp is a PPX for generating printers from type definitions. Here's an example of how to use it while using jbuilder as your build system, and using Base and Stdio as your stdlib.
First, the jbuild file which specifies how to do the build:
(jbuild_version 1)
(executables
((names (w))
(libraries (base stdio))
(preprocess (pps (ppx_jane ppx_driver.runner)))
))
And here's the code.
open Base
open Stdio
type t = { a: int; b: float * float }
[@@deriving sexp]
let () =
let x = { a = 3; b = (4.5,5.6) } in
[%sexp (x : t)] |> Sexp.to_string_hum |> print_endline
And when you run it you get this output:
((a 3) (b (4.5 5.6)))
S-expression converters are present throughout Base and all the related libraries (Stdio, Core_kernel, Core, Async, Incremental, etc.), and so you can pretty much count on being able to serialize any data structure you encounter there, as well as anything you define on your own.
Perhaps beyond the scope of this question, but one might also use a customer formatter with Format.printf
. Consider a simple example:
module Foo = struct
type t = Foo of int * int
let pp ppf (Foo (a, b)) =
Format.fprintf ppf "(%d, %d)" a b
end
And then we might print a value of type Foo.foo
with:
# Format.printf "%a\n" Foo.pp @@ Foo.Foo (27, 42);;
(27, 42)
- : unit = ()
This has the advantage that it can readily be used to also generate a string.
# Format.asprintf "%a" Foo.pp @@ Foo.Foo (27, 42);;
- : string = "(27, 42)"
© 2022 - 2024 — McMap. All rights reserved.