I (dont) like Haskell

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.


15 Responses to I (dont) like Haskell

  1. I notice that we seem to have quite a lot in common.

    Anyway, this sentence is a bit misleading:

    „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.“

    What about e.g. a random value? Yeah, you need a monad for that as well but it’s not the I/O monad.

  2. dasuxullebt sagt:

    You are right. A random vaule is a side-effect. So I should have said „without emulated side-effects“ it is only a function-call. Even though, random values in the end are not a functional concept.

    Actually, I mostly consider all things that need information which doesnt come from the program itself as „I/O“ (because in the end, when you go down to the system-level, most things cut down to syscalls and reading memory which was written by the system), even though that is not what is normally meant by I/O. Strictly speaking, also UI’s are not I/O in that sense – most people consider I/O as I/O-streams like files or fifos. As for a random-value, if it isnt deterministic random that will always be the same (like in CLISP afaik) – which then would again make it theoretically possible to cut down a program to its outcome – it depends on parts of the system which dont come from haskell itself.

  3. Sebastian sagt:

    I always find complaints about type errors confusing. Would you rather your program was happily accepted and then *crashed*?

    Yes, there are very rare examples of valid programs that aren’t accepted by the type system. But most of the time a type error just tells you what’s wrong earlier – in a dynamic language you may not know about it until after you’ve released the software.

    Re: monads and the do notation. Basically I think statically sealing off side effects is a big 100% non-negotiable aspect of programming in the many-core-era. We *will* need some way of doing it, just allowing ad-hoc side effects anywhere isn’t the way to go. So the alternatives are Monads, or Uniqueness types, or Effects typing a la Disciple. Personally I think Monads are currently in the sweet spot because they’re proven and reasonably easy to use and understand. The point is that simply *ignoring* the problem isn’t a valid alternative.

  4. Ian Duncan sagt:

    A few notes:

    You can completely avoid whitespace-awareness by using curly braces and semicolons in a C-like fashion. You can define functions in the REPL by prefixing the function definition with ‚let‘ as in „let foo x = putStrLn (show x)“.

    I’d encourage you to stick with Haskell for a while, because with practice you’ll find that you really learn to like the type system. 95% of the time, you can omit types just fine, but you’ll come to realize that types typically allow you to debug your thinking rather than you having to debug the program that results from your faulty logic.

    Monads took me a while to appreciate, but they are about more than just IO. They allow you to embed all sorts of things into your program by making a your own language functionality. You can use monads for parsing, error handling, list comprehensions, pure state, and more. The beauty of Haskell is that it’s highly abstract, and although it takes a while, if you stick with it, you’ll see a lot of really intelligent ways to approach programming that you may have never thought of before.

  5. dasuxullebt sagt:

    Hm well. I will have to use Haskell in the future anyway. Maybe I’ll get used to it or even like it. Monads are a concept allowing to do some things easier but actually to extend the language I like Lisp-Style-Macros more, and I think, in most of the cases, they are easier.

  6. dasuxullebt sagt:

    I dont think that a type-system really prevents much crashes. They are simply not „mighty“ enough. And actually, I almost never had an issue a type-system would have solved.

    Monads for side-effects are – in my oppinion – too complicated. Clojure’s and SML’s approach of explicitly getting and setting global variables is sufficient imo. I mean, thats basically what multicore-architectures will do: Using anything local directly, while accessing anything public through some special call.

    But as I said in my post, these are just first impressions of Haskell.

  7. Sebastian: I think the problem is quite a bit more subtle than crashing vs. getting compiler errors. Taking the static type system away from Haskell and adding a dynamic one wouldn’t simply result in a kind of Haskell with fewer static checks. I imagine it wouldn’t result in any kind of Haskell at all. The resulting language would presumably be — or become, over time — very different from Haskell, if not with regard to looks, then at least with regard to feel.

    You may be able to make Java dynamically typed without changing it much, but neither can you make Common Lisp statically typed nor Haskell dynamically typed without redesigning other parts of the language as well, and while I adore Haskell’s esthetics, and like it as a programming tool partly _because_ of the powerful way it handles data types, there is quite some complexity associated with its type system and syntax (the latter of which is, in turn, modeled such that it matches the type system) that often distracts me from the problem I’m trying to solve when writing a programme. I assume it is these secondary effects that the OP takes issue with, although he doesn’t clearly say so.

  8. Anonymous sagt:

    You will be surprised at just how mighty Haskell’s type system is! :-) Really, myself originally coming from the Perl camp, I doubted that too — but it is definitely true.

    There’s just so much fun in the type system: Type classes, higher order stuff, phantom types, existential types, composable monads using the coproduct etcetcetc

  9. ertes sagt:

    Hello dasuxullebt. It’s true that Haskell is very different from other programming languages and requires you to put off your usual way of thinking to use it properly. However, your comments about it show that you haven’t actually understood most of its concepts.

    Let’s take laziness: Haskell has non-strict evaluation semantics, which is not just an optimization, but a different way of executing code from ground up. It allows you to express algorithms in ways you have never thought of before. For example, to get a list of primes ‚primes‘ you create an infinite list of all natural numbers and filter it by an ‚isPrime‘ predicate, which in turn checks primality by trial-dividing by all primes. Yes, ‚primes‘ depends on ‚isPrime‘, which in turn depends on ‚primes‘. This works without problems in Haskell. Creating infinite data structures and processing them in seemingly impossible ways is something laziness gives you. This is not optimization, this is a completely different way of thinking.

    Let’s take monads: What they really allow you to do is: When you have a certain programming pattern, then you can create a domain-specific language to express it. State is an example of that. Another example is nondeterminism. Some functions could have arbitrarily many results. Monads not only give you a way of expressing such computations conveniently, but also implement functions at a more general level (i.e. not specific to a particular monad). The true power of monads, however, becomes visible as soon as you learn to combine them (using monad transformers). Combining the list monad and a state monad you get nondeterministic state. Combining the list monad and IO you get nondeterministic effects. Even the list monad alone is something very beautiful. It lets you have a variable ‚x‘, which stands for all natural numbers or something like that.

    Syntax is not ugly, it’s just different. As soon as you get used to it you will love it. This post is from someone, who used to be a fanatic C lover, before he took the time to learn Haskell properly. Now I would never go back to C.


  10. dasuxullebt sagt:

    No offense, but actually, when coming from C I can understand that you like haskell. C does well, when you need to optimize a small algorithm in a portable way, but for anything else, I wouldnt use it.
    But I used Common Lisp for some time now, and actually, I have learned to accept new ways of programming – as I said, I respect the way Haskell does, and I didnt do enough things with Haskell to really give a profound statement.
    I dont think that I will ever like the syntax, because the simple syntax is one of the reasons why I love lisp. But when looking at Liskell, I seem not to be the only one.
    When it comes to monads, it seems to me – meanwhile – like monads are to Haskell about what macros are to Lisp. Even though they differ, at least the arguments for having them, as well as the criticisms against them, seem similar. Seems like Monads are a more „semantical“ way, while macros are a „syntactical“ approach to extend the language’s facilities.

  11. dasuxullebt sagt:

    In general, I dont like anonymous comments.

  12. ertes sagt:

    Was that anonymous? Well, my name is ********[edited by dasuxullebt – you dont have to give your realname]******* and ‚ertes‘ is my nickname. =)

    Yes, the point about monads and Lisp macros is entirely true. About the syntax, well, Haskell tries to reflect its mathematicity. You can love it or hate it. But it was noted in another comment that you can also use free alignment, if you use C-style braces. I would still recommend you to try it out. You may like it in the end, because it’s not just some fancy syntax. It allows you to express things concisely. After all you use indentation anyway, so parentheses are usually just redundant. If you want this redundancy, you can use parenthesis in Haskell, too. =)

    The point about C vs. Haskell was misunderstood. It’s not that I found C powerful, but that I was convinced that C does The Right Thing, implements The Right Paradigm and enforces The Right Way Of Thinking. Today when forced to use imperative languages I prefer C#, D or Python (sorted alphabetically), but none of them would beat Haskell for me. When forced to use a non-Haskell functional language I would probably use F# or OCaml, because of their advanced type systems, probably rather F#, because it allows one to implement monads, although you don’t get anywhere near Haskell’s monads (this is not related to bad language support, but to the type systems — Haskell has the most advanced type system I have ever seen).


  13. dasuxullebt sagt:

    Thank you for giving your real name, but I meant the comment from „Anonymous“ above – in general, I dont publish comments that dont seem to have a proper E-Mail-Address (for legal reasons). I edited your post and removed your real name – I dont want to post my realname anywhere, and so I dont force anybody else to do.

    Well, Common Lisp’s Object System is also very powerful, and actually it does similar things that haskell’s type-system does I think. But maybe it is the wrong way to compare Haskell with Common Lisp.

  14. It’s almost a shame that monads are known mostly for introducing IO. Working with monads (and, more generally, arrows) is a mental shift qualitatively similar to (but smaller than) the enlightenment of getting how to program in a lambda calculus based language.

    But most of your qualms appear to be that it differs from Common Lisp. This is absolutely true. There is less to unlearn than coming from C, but swathes of both languages don’t fit in the other. I have found that on average Haskell suits me better than Common Lisp, so I use it. If Common Lisp suits you better, then stick with it, but it’s worth sticking with it long enough to figure out monads, monad transformers, and the same structures for arrows. They’re a delightful little enlightenment.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:


Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden /  Ändern )


Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )


Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )


Verbinde mit %s

%d Bloggern gefällt das: