OCaml and Reason

Setup

At the minimum these things are required – Opam, the package manager.

Once these are installed, it becomes possible to install the desired version of OCaml, the standard libraries, commonly used third party libraries etc.,

One confusion around “Standard Library” in OCaml is that, there are more than one Stdlib to choose from. Since I’m learning from RWO (Real World OCaml), I’m going with their recommendation.

If you have a working setup, the following checks should yield sensible output.

Pre-flight check:

printenv OCAML_TOPLEVEL_PATH
opam switch

Choose a version of ocaml compiler to install with opam switch. I am using 4.06.1 at this time.

opam switch 4.06.1

Once you have the latest compiler (there is nothing wrong in using an older version of the compiler to learn and use, unless a library you want to use does not work with it etc.,), install the basic libararies you need to start programming.

opam install core utop

The core is the alternative, but full featured, library RWO book recommends. utop is a REPL/interpreter.

OCaml is a compiled language, but it has a very neat REPL in utop. However, if you are coming from another interpreted language background, you have to be aware of ;;.

The ;;s are used to end statements in the REPL, but not in the code saved to a file. This is a clear difference from Python, where one can try out a piece of code in the interpreter and copy paste it to the editor.

S-expressions

S-expresssions are the default serialization format in Core.

S-expressions are paranthetical expressions whose atomic values are strings.

Type used to represent S-Expression is:

module Sexp: sig
  type t =
  | Atom of string
  | List of t list
end

S expression is a tree where node contains a list of children and leaves are strings.

Converting a String to Sexp:

Sexp.of_string ("(1 2 (3 4))");;
- : Sexp.t = (1 2 (3 4))

Constructing a Sexp to string:

Sexp.to_string (Sexp.List [Sexp.Atom "a"; Sexp.Atom "2"]);;
- : string = "(a 2)"

This does not work:

 List.sexp_of_t [1;2;3];;
Error: This expression has type 'a list but an expression was expected of type
         'b -> Sexp.t

But this does:

List.sexp_of_t Int.sexp_of_t [1; 2; 3];;
- : Sexp.t = (1 2 3)

because List.sexp_of_t is polymorphic and it takes a conversion function as its first argument to handle the elemetns of the list to be converted.

It is possible to construct an OCaml value from an S-expression using the same trick with polymorphic types.

List.t_of_sexp Int.t_of_sexp (Sexp.of_string "(1 2 3)");;
- : int list = [1; 2; 3]

The utop (top level) knows how to correctly print s-expressions because of top-level printers that can rewrite values into top-friendly equivalents (pretty printers?). These pacakges ususally end in .top. Use $ ocamlfind to look for these.

Converting a more complex data type into Sexp is easy using the [@@deriving sexp] annotation:

type t = {foo: int; bar: int} [@@deriving sexp];;
type t = { foo : int; bar : float; }
val t_of_sexp : Sexp.t -> t = <fun>
val sexp_of_t : t -> Sexp.t = <fun>

If you notice, OCaml creates the t_of_sexp and sexp_of_t functions for you for using [@@deriving sexp] annotation. Free scaffolding??.

This can even be attached to an excpetion to generate more meaningful exception messages:

exception Good_message of string list [@@deriving sexp];;
    exception Good_message of string list
Exn.to_string (Good_message ["1";"2";"3"]);;
    - : string = "(//toplevel//.Good_message (1 2 3))"

It can even used inline without having to create explicit types:

let l = [(1,"one"); (2,"two")];;
List.iter l ~f:(fun x ->
  [%sexp_of: int * string ] x
  |> Sexp.to_string
|> print_endline)
;;

(1 one)
(2 two)

You can see that the [%sexp_of: int * string] x allowed the inlining of the sexp_of annotation to a tuple of int * string.

References
Missing citation
deriving Missing citation