Hacker News new | ask | show | jobs
by ricccardo 4031 days ago
I've been developing in Haskell for a while and I recently had to learn OCaml to help TA for a course in my university.

I couldn't shake the feel that I was learning "Haskell Light". No pure/impure code (I/O, mutable references, exceptions), no monad syntax sugar, less syntax sugar for pattern matching, much smaller base library, plus surely other differences that my current level of expertise of Haskell is hiding.

Perhaps the simpler semantics make it easier to translate to js (I know haskell->js transpilers are very complex and I'm sure lazy evaluation has a lot to do with it), but in terms of language features, what am I missing in Haskell that makes you more productive/helps you write clearer code in OCaml?

6 comments

OCaml's module system (and conventions associated with it) give a few advantages over Haskell.

- There are good conventions for naming and argument order (and named arguments!) so I don't have to memorize a bunch of different APIs. This is made possible by the module system. It could probably be solved in Haskell with better tooling.

- Modules allow you to, for lack of a better word, make your code more modular. Modules are essentially the same thing as what people use objects for in Java. They let you abstract implementation and program against a particular interface (i.e., a collection of types and values) easily in a way you can't really in Haskell.

Can you give a specific example? If you need abstract interfaces, what's wrong with Haskell's type classes?
OCaml modules have many similar characteristics to Haskell type class[0]. One of the primary differences being that the Haskell type classes handle dictionary passing automatically and support ad-hoc polymorphism. This can be achieved with ML modules but requires bit more labor.

Haskell type classes can make it a bit easier to encode (and infer) interfaces but assume a single implementation per data type. ML modules do not make this assumption and support a higher degree of modularity as a result.

Robert Harper has some extremely good writing out there on this topic (and many more): https://existentialtype.wordpress.com/2011/04/16/modules-mat...

[0] - http://www.mpi-sws.org/~dreyer/papers/mtc/main-long.pdf

Type classes are far less direct to encode. One also requires existential types to get the modularity properties of ML modules and they are a burden to deal with in Haskell.

A good example of something easy to do with ML modules and hard to do in Haskell is the Cohttp library which is a HTTP stack that works using the Lwt async backend, the Async async backend, and a Javascript Lwt backend. It is merely modularized over that interface and you can plug in whatever backend you like.

There are examples of doing similar things (Reflex is modeled this way, e.g.) but it's hairier in Haskell.

I don't know much about Ocaml's modules, however Haskell's type-classes require global uniqueness, which makes them anti-modular. Another problem with Haskell's type-classes is that they are magical, in the sense that they aren't either types or values, hence combining type-classes is always an exercise in frustration. If you want to think of type-classes as being much like OOP interfaces, you're making a mistake. Ironically in Scala, which is the lesser FP language, type-classes are modeled by OOP interfaces and instances are values, so you won't get the same problems.
Offtopic, but I hate the usage of the word "transpiler" and I hate how popular it got.

First of all the word "compiler" is perfectly adequate to convey the meaning of a "transpiler", meaning a computer program whose purpose is to translate code from one programming language into another. The usage of the word "transpiler" only happened because of languages like CoffeeScript, as a word was needed to express that CoffeeScript is just as broken as Javascript, but with syntax changed for no good reason.

But more importantly, many compilers that target Javascript, such as Scala.js, ClojureScript, GHCJS, Dart, are very much not like CoffeeScript, meaning that we are talking about languages with different type and module systems, with big standard libraries, that treat Javascript as bytecode and that need to be compressed with Google Closure to be viable. If you're missing the source-maps, the end result will be much harder to understand than Java or .NET bytecode. Therefore the usage of the word "transpiler" in this context is not only annoying, but incorrect as well.

If OCaml is "Haskell Light" the way C is "C++ Light" that sounds great to me.
For anyone interested in finding out where OCaml is taught, there's a page at http://ocaml.org/learn/teaching-ocaml.html
Simple translation to the native code of your target environment is a feature in itself, especially when you have to debug. I suppose if you can write everything in Haskell and never have to interact directly with your runtime environment (be it native or a browser), you could treat Haskell itself as a bedrock abstraction (http://www.loper-os.org/?p=55). But in many real projects, you do have to work directly with the underlying environment. In that case, the bedrock abstraction is the machine itself (or, for a browser-based app, the JavaScript runtime). So closeness to the machine is a desirable feature in a language and its compiler, to be balanced with other things like developer productivity (so C with manual memory management is the wrong choice for a lot of applications). That's why, if OCaml is simpler to translate to native code or JS than Haskell, I think I'd prefer OCaml.
I have never used either language in teaching. But maybe you have more experience as a TA: do you think OCaml is easier for students because of strict evaluation?
I haven't used Haskell in teaching either. It probably is. My professor does not like lazy evaluation at all (note how i did not insert it in my "haskell light" list of features), he said he played with it at the time this stuff was being researched but he never saw the benefit to offset the complication in semantics.

Our students were mostly having trouble with OCaml being a functional language than anything else. Some of them independently discovered mutable references and for loops and probably wondered why we hid from them such useful constructs! Pattern matching was also something that only the best students took serious advantage of.