A Nice Thing About OCaml Syntax
Lots of people seem to hate OCaml’s syntax: Google “OCaml syntax beautiful” and you get about 90,000 results, while “OCaml syntax ugly” gets around 133,000 — the haters outnumber the enthusiasts by about three to two. In its defense, while I don’t know if I would say OCaml’s syntax is definitely not ugly — I don’t find it offensive, but I’ve been writing some form of ML for almost two decades, and familiarity breeds resignation — there are at least some niceties that, in my mind, ought to be acknowledged.
In particular, OCaml’s syntax for referencing elements within module
namespaces is very general and convenient. In most languages, to
reference an element within a namespace, you have two options. First,
you can use a fully-qualified name. For example, to create an
std::vector
in C++, you’ll usually write something like this:
std::vector<int> v;
If you have lots of expressions that use the same namespace, this can get kind of tedious. Here’s a typical example using some items from the STL:
std::copy_if(v.begin(), v.end(), std::back_inserter(u), std::not_fn(f));
One way to eliminate the multiple instances of std
is to temporarily
import all names from std
into the local scope:
{
using namespace std;
copy_if(v.begin(), v.end(), back_inserter(u), not_fn(f));
}
This works, but is heavy and over-powered: it adds three lines, and it
imports all names in std
for an entire block, while you may only
want to import the namespace for the scope of a single expression.
OCaml addresses this by generalizing how elements of namespaces are
referenced. In C++, the ::
namespace resolution operator
essentially takes a namespace on its left-hand side and a single
identifier on its right-hand side. (I’m playing fast-and-loose with
the definition, but this is morally correct.) In OCaml, the
equivalent operator, .
, also takes a namespace on its left-hand
side, but takes an expression on its right-hand side; so, unlike in
C++, you can use .
to import a namespace over the scope of an entire
expression — and only that expression.
Here’s an example using the List
module:
1 + List.(filter f xs |> fold_left Int.max 0)
Note that the List
module is only opened for the expression on the
right-hand side of the +
.
As an aside, F# cleans up OCaml’s syntax a little bit by dropping
things like unnecessary in
keywords in let
bindings. This cleanup
seems to have resulted in better stats: Googling “F# syntax beautiful”
gets 129,000 hits, while “F# syntax ugly” gets 142,000; if people
aren’t exactly singing the praises of F#’s syntax, there’s a thinner
line between love and hate.