Is Haskell really that… great as a programming language?
Reading lots on Haskell recently I’m beginning to feel like it’s very cool from the CS point of view, but too overcomplicated from the practical one. And all attempts to prove otherwise, as far as I think of them, have failed.
I mean, you can definitely write a useful Haskell application but isn’t the cost too high? Isn’t after all its type system too restrictful? Doesn’t messing with ErrorT IO seem to be much ado about nothing?
Yes, it’s cool when you can reason about your programs in almost mathematical sense. It’s great that you can model the domain with types. It’s nice to have lazy pure code… But when you come to side-effects, stateful computation, error handling, &c simultaneously… Well it starts to feel wrong. Just wrong.
All these are just my thoughts based on short time of learning it. Maybe I’m just too stupid. Maybe I will have this “a-ha!” with Haskell sometime so everything will seem natural to me. But maybe Haskell is just too overcomplicated for actual programming.
It feels like Haskell is actually like maths. Mathematics is all very consistent, you can reason about anything there, you can prove theorems, but when things get complicated they get REALLY complicated. And there is no shortcuts or something like that. And as even tensors don’t fit in my head really well, Haskell may not too.
Think of it like having a programmer to study algebraic geometry for example. Though Haskell seems to be lots easier.
May 31st, 2008 at 0013
You’ve so fucking got it, i have nothing to add.
May 31st, 2008 at 0627
Doing I/O in Haskell is not really any harder than any other language. It is slightly different, in that I/O actions are values and can be passed around, put into datastructures, and so on, but that doesn’t really get in the way.
You mention applying the ErrorT monad transformer to IO. I’m not sure why you’d do this except as part of constructing another more interesting monad (and you’d not expose the ErrorT directly to the user of your monad then).
Despite the impression that most of the tutorials on them give, monad transformers are not really intended to be used in a direct fashion. (Though there are some clever one-liner idioms which take advantage of them.) They’re really intended in the careful construction of other monadic libraries. If you’re seeing lots of lifts in your code, or if your types look like StateT s (ReaderT e IO) a, then you’re doing it wrong. It’s really a good policy to always create a newtype wrapper for your transformed monad, and use GHC’s newtype deriving to derive instances of Functor, Monad, and possibly some of the Monad* classes (MonadReader, MonadState, etc.), though more likely you’ll want to hide those operations, and write your own operations for your new monad in terms of them. You can then simply not export the newtype data constructor from the module, which will give you some guarantees about the primitive operations available in your monad (they all have to be defined in the given module then), and keep your code clean.
But usually, you don’t even touch anything like that — far more often than not, you should stick to a direct style with a pure model and a simple I/O interface on top of it. If you’re familiar with model-view-controller, the model should all be pure code, while the view and controller will be at least partly in IO (but may also include some pure computation in deciding how to interpret input and shape the output).
A monad is a specific type of combinator library. Most monads are even completely pure (that is, executing actions in them has no externally-visible side effects). A combinator library is simply a library which has some primitive operations, and enough ways of combining them that using the library is like using a small embedded programming language. While it can be cool to invent a new monad to make it easy to attack a space of problems, it shouldn’t be done without at least a little thought to whether it’s necessary. Certain problems have very elegant monadic solutions: parsing and nondeterministic search problems being among the best. Sometimes though, a complicated monad isn’t the best approach. Think carefully about the primitives in your library, and how it’s most natural to fit them together. If that happens to be a monad, then great, you get all the Control.Monad operations for free. If it’s not, then trying to make it into a monad is going to produce something awkward, and I suspect that’s what you’ve been running into.
I have an article here which explains the right way to use monad transformers in more detail, as well as this article which describes more carefully how monads are to be thought of, and what the purpose of the abstraction is with regard to program and library design.
On the point of whether Haskell’s typesystem is too restrictive, I’ve never found this to be the case. The typesystem, as far as I’ve experienced, has only prevented me from writing bugs (on occasion even extremely subtle algorithmic bugs!), and helped me to understand how the building blocks provided by libraries are supposed to fit together.
The advantage of the typesystem really shines as soon as you’re maintaining someone else’s code. One fairly recent example was when I made a rather large refactoring to the hs-plugins library. This was an edit that involved deleting half of the source code in hs-plugins (the interface file parser) — code whose purpose I just barely understood, and replacing it with calls into the GHC API, a library with which I had no experience. After working through some type errors caused by hastily replacing things from hs-plugins’ library with things in the GHC API that sounded equivalent, the thing worked on the first try. The tests passed without a hitch, and the new hs-plugins has been in use in lambdabot ever since.
Types are a bit like the nubs on lego bricks which provide structural integrity while suggesting how the bricks should fit together. I now honestly feel a bit lost without them. Using a dynamically typed language, or a language with a weaker static type system feels a bit like clumsily trying to pile nubless lego bricks into heaps and hoping that they’ll stay put.
As for the learning process of picking up Haskell, give it at least a couple months before you start to feel like you can do anything with it, and at least a year before you can expect to be comfortable (at least, that’s about how long it took me, and I’m a mathematician). While not really any harder to learn in absolute terms than most of the imperative languages that people use (for instance, it’s far less complicated than C++ or Java), it is sufficiently different from them that you don’t have the same kind of leverage you might be used to when learning something very similar to a language you already know. It’s a lot more like the process of learning your first programming language than moving between, say, C# and Python.
June 2nd, 2008 at 1242
Wow. Thank you for your comment, Cale.
I will continue to study Haskell. I love mathematics, though I’m bad mathematician (never had enough discipline to study).
I’m just feeling that Haskell is too much information for me. I’m reading a lot on it & it causes temporal brain overflows.
And noting that it took a year for you–a mathematician–to be comfortable with Haskell, I think I shouldn’t be blaming myself & the language for not grasping it as easily as I would like to =)
I just feel Scheme to be much more “natural” in a way, esp. in its way of combining functional & imperative paradigms.
June 3rd, 2008 at 0052
Indeed, Scheme is far easier for novices. I have a great time discussing things like ((if x - +) 3 4) with my girlfriend. No, really.
But Scheme has half the language missing - the typechecker. It’s quite easy to get lost in cars and cdrs in Scheme, and the language doesn’t help. You can certainly help yourself by defining domain-specific aliases, but effectively you’re just adding explicit informal typing by doing that.
It’s much easier in Haskell (or Scala and probably many others) to use tuples and other ad-hoc data structures, without (usually) having to remember which order things are in. You can go as far as you like (within some constraints) in using the type system to help you, letting you think at a different level, letting you delay naming abstractions until you are sure you need to, helping you write very general very reusable small functions. I agree that the type system looks like your enemy at first though, especially if you are already a programmer and used to a compiler that seems pedantic.
June 3rd, 2008 at 0122
@Ricky, I think it’s even not the type system which bothers me. It’s more like doing trivial things like IO =) Or drawing without using StateT with Writer (I can’t find a link, but I saw it on a blog of some cool maths guy today, he was drawing fractals with it).
After all, I think now that Haskell is just very contrasting to the languages I’m used to (like Scheme or, esp., C# & C).
As for getting lost in cdrs–absolutely agree. Defining complex data structures in Scheme demands much care, though again on the other hand it’s arguably much easier to modify them.
I think in general Scheme is much more “dynamic” in a sense of programming in it (i.e. “exploratory”, REPL), while Haskell is more “static” (i.e. think BEFORE you write).
June 3rd, 2008 at 0649
I’ve heard loads of great things about Haskell recently, along with the typical things like how Ruby is amazing, how Java is dead, etc. As far as I see it it’s all hype.
This isn’t to say that Haskell isn’t a great language. Even though my Maths knowledge is terrible I’m still looking to learn Haskell over the summer.
June 3rd, 2008 at 1553
If you only know how to use a hammer, everything looks like a nail
June 3rd, 2008 at 1720
@Mike, I think that the only real mainstream danger for Java is C# with .NET; it’s just a feeling though & I’m biased, so don’t take my words too seriously =)
Though you might need to remember a time when Java was thought of as a toy language, which will never replace C/C++ in mainstream, which is only fit to develop fancy irrelevant applets, &c. So the real truth is that we never know which language may be the next in the mainstream.
@Dmitriy, sure, don’t overlook a screwdriver.
June 4th, 2008 at 1059
I’m in the process of learning Haskell, so take what I’m saying with a grain of salt, but based on what I’ve read and learned, I think Haskell will not ever become as mainstream as C or Java because it is significantly more difficult to learn. However, my belief is that those who have mastered Haskell will be able to create higher quality software more easily than if they used a more mainstream language.
Haskell appears to be moving from academia to “the real world”, so I expect in the next few years we will start to see stories of startups that have a competitive advantage because they have sharp developers using Haskell.
June 4th, 2008 at 1311
@Greg, I agree with you. I think that Haskell is more difficult to learn comparing to other programming languages. And I think that it’s more difficult to learn even as a first language comparing to, say, C#, C or Scheme. C++ in its full is probably the closest “real” (i.e. not esoteric) programming language in difficulty to master to Haskell. But nevertheless while you can start hacking with C++ relatively soon on your road to programming & you can easily drop most of its features & still be able to create something (sometimes it’s even better to drop most of C++ features), you cannot do that in Haskell. You can drop features like Arrows but you have to master hard parts of the language before you can do almost anything useful with it.
It’s like Maths in Physics & Maths in Maths. In Physics you just need to know how to apply things, you need a rather limited subset of Maths & you don’t need to actually know all the implications of, say, integration. But when you study Maths in itself you have to know everything to the deepest levels–what different types of integrals there are, what is topology, how differentiation may be expressed on arbitrary topology &c.
June 4th, 2008 at 1355
jartur, i think it’s not appropriate to compare Haskell to C++. C++ is hard in details and realization, but not too hard in concepts (OOP). But haskell is hard in conceptions of monads, categories, etc. This concepts makes it hard to learn. Remember how OOP was to told to us in the university. It was strange, but then you master with this concept, any OOP language is easy to learn and understand.
June 4th, 2008 at 1402
Dmitriy, I mean C++ is almost as hard to *master* as Haskell. Though they are hard in very different aspects, they both are very hard to become proficient in however.
June 4th, 2008 at 1436
I’ve been using Haskell for personal projects pretty solid for over a year now, and while I wouldn’t say I’ve mastered the language - things like IO become just as second nature as in any other language.
I know it’s not a dynamic language, but once IO actions become Just Another Data Type, the feeling of power you get from slinging around custom control structures on the fly is pretty cool.
The downside is that when you come across an unfamiliar Haskell library all of the crazy combinators and abstractions used can sometimes be a barrier to use. But that doesn’t happen often. Most of the libraries I want to are straightforward.
June 4th, 2008 at 1446
@Antoine, I see. I wonder if I have enough perseverance to wrap my head around Haskell someday.
June 4th, 2008 at 2016
Haskell : where are the apps ? Besides compilers and other such programs written by gurus that would write great programs in assembly if they had to anyway…
Are there examples of non trivial GUI programs ? I’ve only seen slow toys that weigh several MBs.
June 4th, 2008 at 2023
Norman, the most successful apps in Haskell I believe are Darcs & XMonad.
Everything else is mostly CS exercises or mathematical explorations.
This is why I said that there is no evidence to prove that Haskell is actually suitable for general programming.
June 23rd, 2008 at 2249
Haskell is a fine language when you want to give functional programming a go. But as soon as you want to write anything useful it just doesn’t cut it; it is too esoteric.
If you want to try out functional programming, consider using Erlang, F# or OCaml instead.
July 18th, 2008 at 1604
I don’t belive in bad and good languages. I will never say that either ‘Haskell is a good programming language’ or ‘the cost of writing *usefull* application in Haskell is high’. This is completely wrong.
First, comparing tools is incorrect. Try to compare a syringe and a scalpel. What tool should I use for a generic medicine operations? (hello jartur and yours usefull applications).
Second, each tool was designed with a few things in mind.
You can use hammer instead of screwdriver. This is your choice. Nobody will blame you for it (at least I wouldn’t). But ofcourse some things will become more difficult… It is hardly ever possible to make ‘The Great Univiersal Tool For Life and Everthing’.
So why are you saying that the price for writing ‘useful Haskell application’ is too high? What the hell is useful application?
When I need to play with some math model I chose Haskell. When I need to play with some console utils I choose ‘bash/sh’. When I need to deal with some generic ‘high level’ things in imperative manner I choose python. When I need some more ‘low level’ control I’ll write an extension/module for python in C. That’s it.
I guess you are either using a wrong tool (haskell) for some specific ‘useful appication’ or you didn’t get the ‘Haskell way’…
July 18th, 2008 at 1615
cx, actually you can compare tools.
You can compare different models of screwdrivers, or, say, mice & keyboards. The question here is whether your analogy is correct or not. Are different PLs are different models of keyboards or they are more like a scalpel & a hammer? I don’t know.
Actually, this doesn’t even matter. And in general I agree with you & never had said that I don’t, I think.
All in all I think that this discussion is somewhat retarded, like most of abstract PL discussion out there. It has no point.
July 18th, 2008 at 1654
@jartur, you are absolutely right. No doubt.
Actually I was talking about different kinds of tools.
(I have some problems with writing down my thoughts precisely. Alas. Err, sorry. I feel stupid. Please be patient with meI wish I was an author but my brain works in a some different way. And damn I love this way.)
And another point about Haskell. You are facing with a lot of problems during initial studying. And you should better use this situation for your (well, not only your) profit. Try do at least two things:
1. Write all problems down. Maybe later you or somebody else will provide a verbose solution/recommendation/etc
2. Suggest some improvements (libs/syntax/whatever). As in #1 maybe you or someone else could take it into account and make some changes.
Doing this you will definitely provide a help to Haskell newbie (yeah I know about the great mess of Monad tutors) and later it will be really interesting to collect elegant solutions for these ‘issues’.
(imho)