Monday, March 09, 2009

Haskell vs. OCaml, or the ravings of a monomanic insomniac

Until fairly recently, I was a hardcore Haskell hacker who saw little reason to go elsewhere for needs of a higher-than-C level. Haskell is beautiful; Haskell is clever; Haskell has Parsec. A couple of weeks ago, I started using OCaml (after having used ML for a couple of semesters as an undergrad) and realized that you can get a lot farther in life if you are not limited to writing pretty code*.

Since then, I've gone back an forth between "OCaml is the future" and "But Haskell is so pretty." Here are my notes on OCaml vs. Haskell.

Pro-Haskell:

Haskell does datatype constructors right. As in, Haskell datatype constructors are functions whose types are the type of the constructor. For instance, if we have a data type data Thing = C1 Int Int | C2 Bool, we get constructors of types (C1 :: Int -> Int -> Thing) and (C2 :: Bool -> Thing). In OCaml, constructors take explicit tuples. The analogous constructor C1 would need to take something of the form ([int], [int]), not just something of type (int * int).

Haskell does type classes right. Not just type classes, but type class related utilities like deriving. Type classes are often nice for clever things but always nice for development. Being able to derive Show and Eq gets rid of a ton of boilerplate. Not believing in function overloading makes me not believe in ML! >:o

Haskell is way prettier. Small things make Haskell code way easier to read and maintain. (For instance, the support for defining things below functions with where instead of binding everything for let. I should not have to trade off cluttering my toplevel namespace with cluttering my function definitions!

Because Haskell is so clean and concise, it makes you produce prettier code in other languages.

Higher-rank polymorphism and the ability to write down my forall types is very convenient.

Pro-ML:

You can code without being constantly clever! In my senile senescence (which is also absolutely alliterative), I see this as a huge plus. ;)

Not having to work in monads all the time to deal with state in any kind of okay way is a huge productivity plus of SML/OCaml. Don't believe me? I have the following points: 1) 3D IO Arrays, 2) gensym**, and 3) monad transformers (yuck!).

OCaml has very nice library support (Batteries, arrays, etc.).

OCaml seems to have a larger user base, so there are more people doing stuff in it, more people to ask when things go wrong, etc. etc.

Though ML code is more verbose and generally less pretty than Haskell code, it disallows a lot of the clever use of syntax that obfuscates the meaning of Haskell code.

The conclusion is that while Haskell leaves a nicer taste in one's mouth, OCaml might be better for practical purposes, especially if you want to use 3D mutable arrays. It all depends on what you want to do.* According to some fairly high standards of "pretty."** Generate fresh variable names, for instance "__tempvar0." Note that being able to keep some state is nice so you can just increase your variable count each time.

6 comments:

Very interesting. I must say I find Haskell more practical for getting things done than Ocaml, and I've written plenty of both by now. Why? 1) Type classes 2) monad transformers 3) Great FFI 4) generally well-thought-out language design (such as what you mention about data constructors being actual curried functions).

Things I like about Ocaml: 1) Ocamllex and Ocamlparse are much nicer than their counterparts in other languages (and sometimes Parsec doesn't cut it). 2) Camlp4. 3) Functors (however, SML functors are better).

For what it's worth, Ocaml does have arbitrary-rank polymorphism. It's just that the only place you can write qualifiers is inside record types. So, if you want a function that takes a polymorphic argument, you need to declare a record type with the argument type that you want, and then have the function take the record type. Of course, if you want foralls under a whole pile of arrows, you'll need a whole pile of record types. You can also use record types with implicit foralls to do polymorphic recursion, which is kinda hot.

The cool thing is that today, as 2014 approaches, there has been considerable improvement in both the OCaml and Haskell communities toward libraries, packaging systems, tutorials, and even startups devoted to promoting the languages.

I still think Haskell is more prominent, however, possibly because of the origins of OCaml in France rather than in an English-language-dominant environment.