putting Haskell down
I started toying with Haskell in 2006. I picked up the "gentle introduction", was immediately blown away, and recalled why I was so briefly taken with miranda in college. Further into the gentle introduction, I became confused and frustrated. I put it down. I picked it back up after a couple of months and ploughed deeper into it, attempting to build toy programs, with some limited success. Over the years I contributed some trivial packages to hackage that didn't contain any earth-shattering innovations, but did address some basic practical applications that had been overlooked.
As time went on, Haskell seemed to be snowballing. I jumped on xmonad and was hugely impressed (and still use it). I devoured real world Haskell. I cheered on Haskell in forums, I advocated it to friends. I did everything I could to arrive at some point where Haskell would reward me for my loyalty and hard work.
That time never really arrived. I wasn't expert enough to sell myself as one of the few elite Haskell masters. And I couldn't really advocate it to my coworkers. It had taken me years to reach an intermediate stage of Haskell proficiency...how do you convince someone in an industrial setting to undertake a similar journey?
Even then, I soldiered on. Haskell was definitely the tool of choice for programming puzzles, which I love to tackle. with very little emphasis on strict resource or performance demands, and typically having no requirements for interfacing to existing tools, puzzles provide an opportunity for a language to show off its ability to grapple with algorithmic problems. Some of these puzzle solutions would periodically manifest some performance or resource issue that reminded me why I can't bring myself to apply Haskell to real daily coding, but since a puzzle is contrived anyway, I was able to shrug it off. Haskell and I remained friendly on these terms for about a year or so, bringing me to today.
So here I am...not moving forward substantially with Haskell, and probably putting it back on the shelf to focus on other tools. I thought I would enumerate some of the positives and negatives so that others might be able to get some value out of the reflections of someone who put in the time to try to tackle Haskell on its own terms.
- syntax. Haskell has the coolest syntax of any language currently deployed. It is very easy to be taken in by Haskell when reading simple examples that compose functions or exploit pattern matching in an elegant and obvious way.
- tools. GHC is very good. Haskell would have died long ago had developers been left with any of the other implementations.
- types. I will never again doubt the value of strong typing in a programming language.
- community. Pat yourselves on the back, Haskellers. the Haskell community is amazing.
- mind-expansion. Monads and STM strike me as two Haskell developments that really blew me away.
- hackage. There's a lot of stuff in there, and since I use debian, I get the benefit of most of the good stuff being packaged for me without having to deal with cabal.
- laziness by default. Laziness is everywhere in Haskell and there is great effort expended in coding around it or creating libraries that code around it. Laziness by default is a mistake, I am convinced of this.
- some basic stuff is/was missing. I'm a practical working coder. I take it for granted that any modern tool with, for example, have a mature database abstraction (like perl's DBI). Or native SSL. A lot of this stuff has emerged over time with Haskell, but very late relative to other tools.
- type spaghetti. Haskell has a String type. But don't use it (?). But half of the package in hackage do. So you can convert them to Text and/or ByteString. Over and over. And then you end up with boilerplate lying around to shuttle data from one type to another for no other reason than to paper over some history.
- function spaghetti. Why does the Bytestring library include its own set of file I/O functions? Why does the Vector library re-implement a vast array of list-like operations? Haskell has the notion of programming to interfaces via typeclasses, but thats the sort of thing that has to be done right from the start. I don't see how the mess can be cleaned up now.
- GHC pragmas. Most people just cut and paste these until their programs compile. Haskell shouldn't be the kind of tool that encourages blind copying just to get a program to build.
- performance. Average Haskell tends to not be high performance. The elite Haskell masters can create Haskell that performs very well, but unless you are one of this select group, you will not. And when you see what the masters do to achieve some of their feats of performance, you may wonder what you are even looking at.
- memory use. As a result of laziness most of the time. for most exploratory work, this is not an issue. In production systems, it is.
- frankenstein code. Among other issues, working Haskell programmers will experience major problems with Haskell's substandard record implementation, and the impact of lazy IO. Both of these have been addressed through libraries - namely the lens family of packages to address poor record support, and the conduit family of packages (among others) to address lazy IO. Both add a substantial syntactic burden to the code, introducing a lot of weird cryptic operators that will result in near-unreadable programs, and may imply a substantial effort to backport changes into other libraries or older code you are using.
- self-referential design annoyances. Do monad transformers have any real value or do they only exist to pull Haskell out of a corner it painted itself into?
Haskell or something inspired by it could still be a dominant industrial language without sacrificing too many of its cool features.
To move forward at this point requires that Haskell be redefined in a way that breaks backward compatibility. I had high hope that the "Haskell prime" effort might deliver this, but the goals there seemed to be a modest folding in of a few pragmas. I advocate more sweeping changes.
- Strictness by default.
- Fewer basic types - fix the String problem by having one type that is the one that people should use, etc.
- No pragmas.
- No goofy type annotation syntax for performance tweaking.
- Fix modularity so that "cabal hell" is impossible.
- Basic "batteries included" libraries (see the Go standard library for a great example) and include these in the core deployment.
- let Agda, etc be the focus of research/academic development.
I'm not that enthusiastic that any of the above will ever happen, mostly because the most-skilled and best informed Haskell masters have internalized these problems and the various hacks to address them.
In the meantime, I'm picking up Racket and Rust more often. Racket gives me functional goodies and a willingness to make sweeping changes (like Typed Racket) to meet the needs of the future. Rust looks like a fantastic halfway point between Go and Haskell that provides a lot of type goodies out of the box.
last update 2013-01-09