138 karma · joined April 26, 2010
In fact, I love and use both Haskell and Ocaml, and I view the two languages as cousins. Both are functional. Both have features the other doesn't. Ocaml has the best module system in the business, with functors for module abstraction (unbelievably useful). This is much better than the current Haskell module system, though Backpack may narrow the gap. Ocaml also has polymorphic variants, which are surprisingly useful. Ocaml has some convenience features like named/optional arguments that Haskell doesn't. And oddly enough, the lack of purity in Ocaml (if used judiciously) can be a real win. You can do imperative programming without jumping through a lot of hoops. You can have code which is purely functional from the outside but which uses imperative idioms internally for efficiency (yes, I know about unsafePerformIO in Haskell, but it's much easier to do this sort of thing in Ocaml). And Ocaml is usually faster both in compilation time and run time.
My overall take on it is that I prefer Haskell for small-scale programming but I prefer Ocaml for large-scale programming. YMMV.
This post/rant would be more persuasive if one got the impression that the author knows more about what he's talking about. One crucial aspect of monads Bracha ignores is that monads have statically-checked types (at least in languages like Haskell) which label what side effects can or (more importantly) cannot happen when a function (and/or monadic action) executes. This prevents impurity (in e.g. the IO monad sense) from breaking out into pure code; pure code that used impure code would have to change its type or wouldn't compile. This is a huge, huge, huge, huge win. It means that you can't "break" purity; pure functions stay pure. In contrast, a function in Erlang (a dynamically-typed functional language which is actor-based) which sends a message cannot be assumed to be a pure function, even in the event that a particular sent message always evokes the exact same reply. This is not to diss Erlang, which is a terrific language in many other ways (nor is it an attempt to diss Newspeak either).
Note also that Scala (a statically-typed language) has an actors library but also AFAIK has some support for monads (Scala experts can elaborate here). If only one concept was necessary in Scala, why have two?
Another point is that monads are used for a great deal more than modeling imperative features in pure languages (though that is a major part of what monads are used for). What about modeling functions-that-can-fail via the Maybe monad, or nondeterministic computations via the list monad, or computations that can raise error conditions via error-handling monads, or...? the list goes on and on. Monads can make any of these kinds of functions much easier to write and to compose. When one programming concept finds so many disparate uses, it's just possible that it's worth looking at closely.
I realize that Bracha is not a fan of static typing (his views on typing i.e. pluggable types have never seemed especially workable to me, but whatever, it's his itch so he can go scratch it), and conversely he is a fan of introspection in ways that are difficult to put into a statically-typed functional language. So I understand why he isn't a Haskell fan, and I have no problem with him pursuing another research direction. But this post smacks of (a) sour grapes that Haskell gets more attention than Newspeak, and (b) lack of understanding as to what monads are all about. Perhaps if he would read some of the tutorials he refers to a little more closely than he has, he would get it.
I think this is one reason why a book like SICP (http://mitpress.mit.edu/sicp) is so helpful; you have to learn a new language (Scheme) and then learn unfamiliar design patterns applied to larger and larger-scale problems, and along the way you pick up a lot of generally-applicable software engineering knowledge that transcends Scheme.
Another really useful trick is to have to maintain/fix someone else's badly-written code. Nothing teaches good design better than having to fix bad design.
Note, though, that some of what the author calls "tactics" (like loose coupling) actually span the range between tactics and "strategy". Writing pure (referentially-transparent) functions that can't do anything other than transform their inputs deterministically into their outputs is loose coupling on a small scale (tactics). Writing classes which are not highly dependent on specific other classes for their functionality is loose coupling on a large scale (strategy).