I’ve been doing a lot of Haskell programming lately. At first, I really liked it.
Well, I like the syntax. Everything is automagically curried, making the syntax for partial application very nice. The syntax for creating records and algebraic data types is great. List comprehension is better than any other language I’ve used. Stream syntax is natural.
But the more I use it the more I dislike it. Laziness was cool at first. The more code I write in Haskell, however, the more laziness is becoming a problem. In one project I’m working on, everything is in a monad, partially because I need strictness (partially because I need threads, state, and continuations). I’m working on Accelerate, and to deal with laziness, they sprinkle in force, seq, !, and Delayed type classes just about everywhere. It’s necessary as the embedded language is meant for GPU and other parallel programming, where laziness is a problem.
More irritating than the language itself is the system. Cabal, the package manager (similar to Perl’s CPAN), is terrible. It can’t uninstall anything, for one. It seems to fail at dependency resolution half the time, installing the wrong versions or just failing with ‘unsatisfied dependency’ leaving me to install the dependency myself. This would be less irritating if I didn’t need to install multiple version of every package, due to my next point.
Backward compatibility. In fact, compatibility, in general. Packages for 6.12 don’t work with Haskell 7.0, and packages for 7.0 don’t work for 6.12, or 7.2. Nothing is compatible with anything! There are usually multiple versions of each package in the repository, but cabal just goes right on installing the most recent version. This is made worse by every other library requiring a difference version of some dependency, so I need to install and manage multiple incompatible version of numerous libraries. And cabal does a miserable job of helping.
Now, let me compare to me compare to my work-flow in Scheme (my current favorite language). I download any libraries I need, and manually stick them in ~/lib/scheme, which I tell Chez to search for any libraries I need. If they aren’t libraries, find, I manually (load ""). Not as handy as cabal install package, but, it also means if I need multiple versions, I can rename/manually specify the versions. More importantly, Scheme is has standard, that most schemers follow, so I never need multiple versions of anything, and all the libraries and implementations are pretty much compatible.
Now, in Scheme, I don’t have laziness, or nice syntax for curried/partial application, streams, records, or ADTs. But, I have macros, which let me extend the syntax arbitrarily, so if I really want them, I can add them. And laziness is easier to encode than get rid of, so if I want laziness, I can add that too.
What’s my point? Well, I guess: ARRGG HASKELL, I’m going back to Scheme.