Till now, I mostly avoided using Haskell. As I have often written, I like Lisp, and in some lecture I already had to work with StandardML. But now, due to a lecture, I have to use Haskell.
Actually, as far as I see, Haskell does have a lot more free maintained libraries to use for UI-Programming, XML-Processing, etc., than Common Lisp, and there will be a Perl 6 Implementation written in Haskell. Seems like Haskell has a huge community. So there must be something about Haskell.
Well, something that always kept me from using Haskell, is its syntax. Not only is it case sensitive, but also denominators with capital first letters are semantically different to those with small letters. Furthermore, it is whitespace-aware, which is something I really dont like. Well, in Python, at least you always have to end a line, while in Haskell this is not always that clear. It confuses me. Actually I dont like to use a language where a huge part of debugging just consists of finding out where and why the syntax in an expression is wrong. Something which is at least interesting to me is Liskell, putting lisp-syntax and macro-facilities (as far as I read) on top of Haskell, but I actually have never tried it so far.
Then it is not possible at all to change definitions afterwards, while programming. You have a REPL, but it does not understand definitions, only simple expressions. You will always have to completely reload your program – well, I am sure there is a possibility to do this, but I couldnt manage to do, and of course, it conflicts with Haskell’s purely functional approach to change definitions afterwards – this may be good as soon as your program is ready-to-run, but actually, I think, for convenience, at least there should be a simple possibility to change definitions while developing an application, which at least recompiles only the parts of the program which do hardly depend on the definition.
Haskell seems to be very formal. Every expression has a type. If types dont match, you are warned. That is very useful, but on the other hand also very restrictive. It can be helpful to prevent bugs, but it can really get on ones nerves, if something doesnt work for some reason you cannot find – and reasons can be missing brackets, whitespaces or arrows – which is due to the complicated syntax.
Lazy Evaluation sounds interesting, even though I havent seen any example where it really makes programming easier. Actually, I think it gives you less controll over the program flow, and makes it hard to estimate time and space needs of your code. I have already read somewhere (I dont have the link anymore, sorry), Lazy Evaluation is given as an argument against having a notable macro-mechanism in Haskell – since anything is evaluated only once anyway, this isnt needed.
Actually this point made me wonder about what a haskell program does anyway. Inside Haskell, it is not possible to do I/O without having monads or something else like push-arguments to “emulate” imperative programming. A “pure” Haskell-Program without emulated I/O is only a function-call, which has a unique return-value, that is already determined at compile-time.
That is, as soon as you are really only using functional concepts (well, I/O-Monads may be embeddable into functional programs, but anyway, they just embed side-effects which are not functional), the compiler compiles anything it can, throwing away anything that is not needed. But actually, thats what every optimizing compiler should do. Even a C-Compiler throws away declarations and blocks which are obviously never reached (except when explicitly otherwise declared). Ok, well, maybe the haskell-language can do this a little better – i.e. you can do things like reading streams into infinite lists, or create formally infinite lists. That is a nice thing to have for some problems – also for Common Lisp there are libraries extending the language to be able to do this. But no reason for using haskell, at least to me.
When it comes to monads, it gets really weird. I really tried to like monads – and actually, the mathematician inside me likes them. They are beautiful, from a formal point of view. But using them for programming is just weird. Using Haskell’s Bind-Notation ( >>= ) is not really convenient, and actually, just passing the statefull thing as an extra argument is shorter and clearer. I think thats why they added their do-notation for usage with monads.
Formally, the do-notation encapsulates monads into a more convenient syntax, which makes things easier when beginning with monads. But when just looking at this syntax without considering the formal background, what remains is a complicated imperative language, which looks similar to python except that its less usable than C. C – compared to Haskell – is a lowlevel-language, which is the reason why in C you have to know a bit about the underlying architecture and the kind your computer works, while Haskell is a high-level language which abstracts most of the lowlevel-stuff, but makes itself complicated by introducing a lot of highlevel concepts. Abstract Nonsense.
I think, functional programming is somehow the paradigm of the future. But it has its limits, and I think one has to accept that. I/O and user-interaction is simply stateful and I think it is the wrong way to try to enforce it into the functional world. And sometimes states are simply more elegant than any functional approach. I think, the way SML does it, is somehow a good compromise. And even though I dont like clojure, I think it also does this part well, using the functional approach when usefull, but knowing and accepting its limits.
Anyway, Haskell is a product of many people’s work, it is not the language for me, but I respect it, as I respect Clojure, even though I dont like it. I think I would prefer scheme because it is most similar to common lisp, but also SML is a good language, and what I have seen from OcaML seems to be also ok.