The tutorials being developed by the ocaml.org team are wonderful, but I actually prefer something a little different, so I’ve started writing some stuff on the following (loose) principals:
-
Starting with a repl is a mistake. The whole ‘;;’ business is an impediment, and furthermore the repl is misleading: it prints the type and value of the forms it evaluates, except for let definitions, in which case it prints the definition, which is not the value of the let form. So for me at least it is better to start with code in a file and a simple makefile for compiling. The repl is something you use for exploratory programming after you’ve learned the language.
-
Failure is edifying. Most tutorials give only examples that work. But users like to explore, and discovering what does not work is just as valuable as discovering what does work. Case in point:
let
forms. It’s trivially easy to write let forms that do not work and produce totally opaque (for newcomers) error messages. (Google “Henry Petroski” for more on the importance of failure in engineering.)
So I’ve started writing a bunch of small demo source files with liberal explanatory comments, each with a simple makefile and a test file (using ounit2), the intention being that the user can tweak the files, run make, and see the results, quickly and easily.
Example: let
forms are surprisingly complicated in OCaml. One of the first things I did getting started was try some let
stuff, and was immediately stymied. For example, I can write 7
as a top level expression; why can’t I write something like the following?
let f = fun x -> x + 1
2
Of course its obvious if you know OCaml; but even after you learn that whitespace is not a delimiter, the error message is mystifying:
1 | let f = fun x -> x + 1
^
Error: This expression has type int
This is not a function; it cannot be applied.
Why on earth is OCaml telling me the obvious? Well, because of type inference, etc. Similar puzzling errors and warnings happen when you start recklessly using the semicolon to form expression sequences.
So in short, I’ve started out by working through various ways that let
can be used, including ways that one might expect to work but don’t, and trying to find good explanations for the errors.
Here’s one I still don’t understand:
let x = 1 in () (* ok, evaluates to () *)
let y = 2 in () (* syntax error on 'in' *)
I can’t explain exactly why this error occurs.
In any case, here’s the link if you’d like to take a look at what I’ve got so far (bear in mind this is a WIP). Feedback welcome.
(note that it is on the dev
branch)
A case where I think this approach is particularly helpful is “expression closures”, see https://github.com/obazl/demos_obazl/blob/dev/ocaml/letforms/closures/a.ml