August 28, 2017

OCaml for the impatient

The web's quickest and dirtiest OCaml getting started guide

Ocaml is a rad language with some regrettably underdocumented parts. Or, perhaps, overdocumented – since OCaml attracts people who are interested in rigorous correctness, what documentation exists tends to be rigorous and correct, and also tedious. This guide will be none of those. Let’s go!

Install OPAM

This guide will require you to install OCaml and OPAM before we can really do anything. OCaml for obvious reasons, and OPAM because it’s the standard OCaml package manager and is required to install everything else.

I won’t cover how to do that because I just followed the Real World OCaml Installation Instructions and it seemed to do fine. If you get OPAM installed and working, you should be able to move on to the next step.

Choose an OCaml version

It is strongly recommended that you pick an OCaml version that your project will compile against. You can do that using the opam switch. First, run the following to list all the versions available (your output may differ):

$ opam switch list
--     -- 3.07    Official 3.07 release
--     -- 3.08.0  Official 3.08.0 release
--     -- 3.08.1  Official 3.08.1 release
--     -- 3.08.2  Official 3.08.2 release
--     -- 3.08.3  Official 3.08.3 release
--     -- 3.08.4  Official 3.08.4 release
--     -- 3.09.0  Official 3.09.0 release
--     -- 3.09.1  Official 3.09.1 release
--     -- 3.09.2  Official 3.09.2 release
--     -- 3.09.3  Official 3.09.3 release
--     -- 3.10.0  Official 3.10.0 release
--     -- 3.10.1  Official 3.10.1 release
--     -- 3.10.2  Official 3.10.2 release
--     -- 3.11.0  Official 3.11.0 release
--     -- 3.11.1  Official 3.11.1 release
--     -- 3.11.2  Official 3.11.2 release
--     -- 3.12.0  Official 3.12.0 release
--     -- 3.12.1  Official 3.12.1 release
--     -- 4.00.0  Official 4.00.0 release
--     -- 4.00.1  Official 4.00.1 release
--     -- 4.01.0  Official 4.01.0 release
--     -- 4.02.0  Official 4.02.0 release
--     -- 4.02.1  Official 4.02.1 release
--     -- 4.02.2  Official 4.02.2 release
--     -- 4.02.3  Official 4.02.3 release
--     -- 4.03.0  Official 4.03.0 release
--     -- 4.04.0  Official 4.04.0 release
--     -- 4.04.1  Official 4.04.1 release
--     -- 4.04.2  Official 4.04.2 release
4.05.0  C 4.05.0  Official 4.05.0 release
system  I system  System compiler (4.05.0)
# 250 more patched or experimental compilers, use '--all' to show

Pick the most recent one and pin yourself to that, then activate your configuration (the opam switch command output will remind you to do this):

$ opam switch 4.05.0
$ eval `opam config env`

The first time you run opam switch for a version you don’t have installed, it will download, compile, and install that version.

Creating your Project directory

The first thing you need to do is to create a project directory. I’ll be calling my project “ocamltestproj”; keep that in mind, it’ll be relevant later:

$ mkdir ~/Projects/ocamltestproj
$ cd ~/Projects/ocamltestproj

Next you need to add at least one .ml source file to the folder. This is important, and if you’re used to other languages that demand setup before you start coding you might miss it (I did). So far, I’ve been organizing code into two directories: bin/ and lib/. So, make those two directories now:

$ mkdir bin
$ mkdir lib

Finally, we’ll get a source file in. Create a file named bin/main.ml, and add the following to it:

let () = 
    print_endline "Hello World"

In this configuration, the files in bin will have access to those in lib, via Lib.<module> (e.g., if you have a source file named lib/test.ml, you can refer to it in bin/main.ml via Lib.Test.

Add your project to OPAM

Next, we’ll add your project to your local OPAM repository so we can use OPAM to install its dependencies. Run the following command to create your project and instantiate an opam file for it. Note that it will prompt you to edit the OPAM file; feel free to save your invalid opam file, you can always run opam lint later.

$ opam pin add ocamltestproj . -n                                                                                                         ──(Mon,Aug28)─┘

After this is done, rename the opam file to include your project name:

$ mv opam ocamltestproj.opam

Set up jbuilder

You can install merlin and jbuilder as easy as:

$ opam install merlin jbuilder

Setting up jbuilder entails creating a jbuild file for each source directory. In bin/jbuild put the following to denote the program’s executable (jbuild config is some sort of lisp, so anything followed by ; is a comment):

(jbuild_version 1)

(executable
  ((name main)                 ; The name of your entry file, minus the .ml
   (public_name OcamlTestProj) ; Whatever you like, as far as I can tell
   (libraries (lib))))         ; Express a dependency on the "lib" module

In lib/jbuild, put the following:

(jbuild_version 1)

(library
  ((name lib)
     (libraries ())))

Notice the empty “libraries” declaration, we’ll come back here.

Now, you should be able to run jbuilder build from the root of your directory. If this succeeds, you will find a new _build directory in your project root. You should be able to run your program like so:

$ ./_build/default/bin/main.exe
Hello World

You will also find a .merlin file in each source directory with a .ml file in it. This will tell merlin about your source files and dependencies and in general let it work properly.

Adding a dependency

At very least, just about every ocaml program will want to include the “core” library, which is essentially ocaml’s standard library.

First, install it via opam:

$ opam install core

Then, add it to lib/jbuild:

(jbuild_version 1)

(library
  ((name lib)
     (libraries (core))))

Now you can use Core in your project! Since bin/ depends directly on lib/, it has access to the library too. Update bin/main.ml to use it:

open Core

let () =
    print_endline "Hello World"

Next, run jbuilder build. Your project should build successfully (importantly, this also adds the new dependency to the .merlin files). You can repeat this process any time you need a new dependency.

Congratulations! You should have all you need to get started.

Bonus section: Setting up VSCode for OCaml development

Thanks to Merlin, just about any code editor can field a decent OCaml integration. I like VSCode’s because it works almost out of the box (and because the Vim plugin actually uses Neovim under the hood).

Just open VSCode and search for and install the OCaml extension (package: hackwaly.ocaml). Since JBuilder handles the .merlin files for you, you should have rich autocompletion and linting out of the box. Next, you can open your project root.

You can also configure your build command to use jbuilder. Just create a file called .vscode/tasks.json in your project root and put the following in it:

{
    "version": "2.0.0",
    "tasks": [
    {
        "taskName": "build",
        "type": "shell",
        "command": "jbuilder build",
        "group": {
            "kind": "build",
            "isDefault": true
        }
    }
    ]
}

Now, pressing command+shift+B (or whatever the windows equivalent is) will build with jbuilder automatically. Remember that jbuilder generates your .merlin files, so you’ll want to rebuild whenever you add a dependency.

Now you should have all you need to start poking around OCaml. I, like everyone, recommend using Real World OCaml as a guide.