Ocaml and JSON
Manipulating JSON (JavaScript Object Notation) elements is amazing and allows to move data around between different programs easily. The only thing you need is to be able to write and read JSON in all your programs. Though this can be simple in some languages, other will require some work to.
OCaml being strongly typed, serializing / deserializing object is less obvious than in, say, Python.
The tools
Yojson: low-level JSON library for OCaml
ppx_deriving_yojson : writing json
To get them, simply use opam:
opam install yojson
opam install ppx_deriving_yojson
Optionnal, for vim users
If you have not done it already, these tools will help you navigate through the different functions proposed by the above packages. They allow to have “intellisense” for OCaml.
Note that you have to create a .merlin
file in the directory where you are working, to help vim
find the relevant packages.
PKG find yojson
Type to JSON
What is PPX ?
Writing code for each type to turn it into JSON is particularly boring and can lead to errors. In many languages this is straightworard. Like using json.dumps(obj)
in Python. The PPX language is a feature that provides a new API for syntactic extensions in OCaml. deriving yojson generates three functions per type:
# #require "ppx_deriving_yojson";;
# type ty = .. [@@deriving yojson];;
val ty_of_yojson : Yojson.Safe.json -> (ty, string) Result.result
val ty_of_yojson_exn : Yojson.Safe.json -> ty
val ty_to_yojson : ty -> Yojson.Safe.json
So what happens is that, during the compilation process, the functions ty_of_yojson
and the others will be, automatically and silently, generated and the compiler will not complain that they are missing - though you never had to write them.
Nested types
Let’s give it a try ! And come up with a nested type.
type t = {x: int; y: int} [@@deriving to_yojson]
type u = {s: string; pos: t} [@@deriving to_yojson]
let () = print_endline (Yojson.Safe.pretty_to_string (u_to_yojson {s= "hello"; pos={x= 1; y= 2}}))
ocamlfind opt -package ppx_deriving_yojson -linkpkg -o testJson.byte testJson.ml
./testJson.byte
rm testJson.byte
And…
{ "s": "hello", "pos": { "x": 1, "y": 2 } }
It worked :)
Learning more
Real World OCaml: Functional programming for the masses by Yaron Minsky, Anil Madhavapeddy and Jason Hickey is a good introduction to OCaml.