I’ve been diving into OCaml recently. It’s a fun language and a bit different as the statically typed, type-inferencing languages go. OCaml is not only a full-bore functional programming language; it also compiles to native code on many platforms and it's very fast. You can’t call it a propeller-head language. That won’t do. People do some incredibly practical work in OCaml. It’s sort of the functional programming language equivalent to Python.
Part of the fun of OCaml is its syntax. It's a little quirky. List elements are separated not by commas, but by semicolons:
List.iter GlDraw.vertex2 [-1., -1.; 0., 1.; 1., -1.];
There are some other strange choices as well. If you want to send a message, you use the hash symbol between the object name and method rather than a dot:
method run result =
result#test_started;
self#set_up;
try self#run_test result with
TestFailure message ->
result#add_failure test_name message;
self#tear_down
I’m not sure why the language designers made these choices, but I suspect that history has something to do with it. OCaml is derived from Caml which, in turn, is derived from Robin Milner’s ML. Language design is evolutionary and early choices, to some extent, constrain later choices. One thing that is obvious, though, is that OCaml definitely isn’t in the C language family so if you're used to Java, C++, or C#, it does look a bit alien. For me, it's been hard to tell whether its syntax is any more inconsistent than the syntax of C-derived languages. It may just be that my eyes aren’t tuned to it yet.
It’s hard to talk about it without devolving into a language war, but syntax does matter. And, it affects more than aesthetics, it can affect correctness as well.
One of the bits of syntax I love the most is the way that Ruby handles instance variables. In Ruby, you preface them with an ‘@’. My first impression when I saw this was “Wow, what a pain! You have to have ‘@’s all over the place.” But, as I used Ruby, I appreciated how important that choice was. In C++ and Java, it is relatively easy to assign an instance variable to itself in a constructor. That never comes up in Ruby. Moreover, you aren’t tempted to make up silly names to disambiguate constructor arguments and instance variables.
No, I think syntax does matter, and I don't think it's wholly subjective.
Here's a quicksort in Erlang:
qsort([]) -> [];
qsort([Pivot|Rest]) -> qsort([ X || X <- Rest, X < Pivot])
++ [Pivot]
++ qsort([ Y || Y <- Rest, Y >= Pivot]).
And, here's a similar quicksort in Haskell:
quicksort [] = []
quicksort (s:xs) = quicksort [x|x <- xs,x < s]
++ [s]
++ quicksort [x|x <- xs,x >= s]
Which one do you like better? Which one seems easier on the eyes? Are there some objective criteria for syntax in language design?

Comments (15)
I've always thought "OCaml is to Haskell as Perl is to Ruby". Haskell and Ruby pride themselves in their purity, whereas OCaml and Perl pride themselves in practicality.
Posted by Brock Wilcox | October 8, 2007 10:30 AM
It's funny. I said the same thing to a friend the other day, but substituting Python for Perl. :-)
Posted by Michael Feathers | October 8, 2007 10:32 AM
Looking at the two quicksort implementations, I tend to like the Haskell better. There is less line noise in the Haskell version, but the Erlang version has better variable names.
Posted by Anthony Moralez | October 8, 2007 12:08 PM
... fair enough, substituting Python for Perl is often a good idea ;-P
Posted by Gary Capell | October 8, 2007 1:00 PM
Hm, the Haskell version takes O(n*n) time since the partition is not the Quicksort one.
Posted by Anonymous | October 8, 2007 7:38 PM
The Haskell solution looks nicer.
From reading stuff like programming.reddit and the like (internetzzzzz!) it seems Haskell is more popular than OCaml too.
I am soooo glad that PHP is hardly ever mentioned anywhere though :-)
Posted by she | October 8, 2007 9:42 PM
I don't think that the two versions are in any way clearer than their lower level counterparts (C/C++). Too many syntax tricks are usually evil for quality code, and I don't see the two being in any way looking good. Shorter, yes. Better? Not for me :)
Posted by Dorin Lazăr | October 9, 2007 3:31 AM
I'm not sure where anonymous gets "the partition is not the Quicksort one". The original quicksort used the head as the pivot, but no choice of pivot eliminates the O(n*n) worst case, although median-of-3 does make it less likely.
Posted by Anonymous | October 9, 2007 6:27 AM
"Too many syntax tricks are usually evil for quality code, and I don't see the two being in any way looking good."
How is C++-comparable speed while offering GC to be considered evil?
Syntax tricks are only a problem when you don't have a good compiler to catch typos.
Posted by Robert Fischer | October 9, 2007 2:42 PM
What a poor comparison between Erlang and Haskell.
At least use similar variable names so that you can make a fair comparison. Refactoring to make the names identical highlights that the only differences are parenthesis and the end of command/end of line markers. The two are so close to identical it's not worth discussing the differences.
Posted by Tom | October 10, 2007 2:30 PM
For those who care, here's the Ocaml code for quicksort:
If you want to be persnickity, you can include the source for partition if you want:
Ocaml doesn't have the neat list comprehension syntax Haskell does, which allows you to inline partition.
In my experience, the syntax "tricks" usually aid in comprehension of the code, rather than hinder it. It's amazing how many algorithms are easily expressed in terms of a "in this case, do this, in that case, do that" style.
Posted by Brian Hurt | October 10, 2007 9:16 PM
I agree with Dorin: there's no reason for the extra syntax of list comprehensions to do something this simple:
quicksort [ x | x <- xs, x < s ]
is no better than
quicksort ( filter (<s) xs)
OTOH, there are more complicated list comprehensions that would make very ugly and complex code written any other way.
Also in Haskell you would just use partition:
quicksort [] = []
quicksort (s:xs) = quicksort yz ++ [s] ++ quicksort zs
where (ys,zs) = partition (<s) xs
Posted by Greg | October 11, 2007 12:16 AM
Both versions remind me of Prolog, I can't see any big difference between them. I'd call them "logical" more than "functional".
Posted by Gabriele B | October 12, 2007 2:41 AM
While I agree with the gist of your article, I think your quicksort example isn't very good for comparing syntaxes. If you use the same names in the Haskell and Erlang code, the two functions become almost indistinguishable. The differences that do remain, I think, are purely subjective in value. A
qsort([]) -> [];
qsort([Pivot|Rest]) -> qsort([ X || X ++ [Pivot]
++ qsort([ Y || Y = Pivot]).
vs.
qsort [] = []
qsort (Pivot:Rest) = quicksort [X|X ++ [Pivot]
++ qsort [Y|Y = Pivot]
Posted by Alex Rubinsteyn | December 3, 2007 7:27 PM
List comprehension exists in OCaml, you just need to activate it.
With list comprehension, you can write:
#load "camlpof.cma";;
let rec qsort = function
| [] -> []
| h::t -> qsort [ x | x [h] @
qsort [ x | x h ] ;;
As mentioned above, you don't need list comprehension.
open List;;
let rec qsort = function
| [] -> []
| h::t -> qsort (filter (( > ) h) t)@
[h] @
qsort (filter ((
or, a faster version using partition
open List;;
let rec qsort = function
| [] -> []
| h::t -> let (xs, zs) = partition (( > ) h) t in
(qsort xs) @ [h] @ (qsort zs );;
By the way, several syntax extensions are available to improve the readability of "List.iter". With these extensions, one may rewrite your first example
for each i in List [-1., -1.; 0., 1.; 1., -1.] do
GlDraw.vertex2 i
done
Posted by More versions for OCaml | December 18, 2007 7:17 AM