Why isn't Haskell popular in Industry?

This question was recently posed (and closed!) on stackoverflow. The top voted reply is so good I thought I'd replicate it here! I'm afraid all I know of the original author is their "Orphi" posting name.

It's tongue-in-cheek and broadly true, although I'd argue the details of a few points. I think it's interesting that it doesn't contain the main reason blocking me from using it on a daily basis. More on that in a moment.

First, here's Orphi's response:

  1. Nobody's ever heard of it. No one's going to use something they don't know exists.
  2. It's unpopular. People assume that the most popular language is the best language, because if it wasn't good, it wouldn't be popular. This is actually untrue; as you can see, the most popular language is the most popular language. To put it another way, Haskell is unpopular because it's unpopular. This is what Haskell programmers refer to as "recursion", and despite what imperative programmers tell you, it's extremely common in The Real World.
  3. It's different. People are always afraid of what's different.
  4. It's difficult. People think that Haskell is difficult to understand or difficult to learn. This is almost certainly related to point #3. It's also related to the fact that the Haskell community is populated by people who casually remark "a monad is just a monoid in the category of endofunctors, what's the problem?" and expect normal human beings to comprehend this.
  5. It's risky. Most companies don't want to be the first to use something. Haskell isn't being used by many people, so not many people want to try it. (See this recursive unpopularity argument again?)
  6. Can't hire programmers. First, by #2, there aren't many programmers who already know Haskell. Second, most people believe #4, which means you can't train programmers to use Haskell. (At least, it would if it were actually true.) A language that you can't hire programmers for is a very, very risky proposition indeed. (Which leads us back to #5.)
  7. Libraries. This is probably the big one, so I'm going to spend some time on it.
    • Quality. We have the quantity. We do not yet have the quality. Most of Hackage is one-man hobby projects with little to no documentation. Some of it is incomplete, some of it has long since bit-rotted, some of it malfunctions if used in certain ways.
    • The Outside World. If you want a binary heap tree, Hackage probably provides a dozen implementations. If you want to connect to an RPC server and fire off a few procedure calls... good luck with that. Same deal for talking to databases, accessing OS resources, manipulating binary file formats... You'll basically have to write everything yourself from scratch. This is a big deal for commercial work.
    • Multiple incompatible libraries. You can, in fact, connect to a database in Haskell. Trouble is, at the last count there's about a dozen libraries for doing this, and it's bewildering trying to figure out which ones are actively supported and which ones are zombie projects that stopped working years ago. It's also not as simple as hooking up an ODBC connection; there are different backends for each library and each DB target. Yay. :-/
    • Windows. Almost all the important libraries (for cryptography, binary file formats, network protocols, data compression, talking to databases, etc.) are Haskell wrappers around C libraries. And these all fail to build on Windows. Given that Windows is
      the single biggest target platform on the market, this is a big deal.
  8. Unpredictable performance. This is way, way down at #8. Most people don't know enough about Haskell to even know this. Most people just assume that "Haskell is slow". This is demonstrably untrue. What is true is that it can be hard to predict the performance of a Haskell program. Subtle, apparently irrelevant changes can sometimes make big performance differences.
  9. Correctness. Most companies don't give a **** about correctness. They don't care about quality. They just want to shovel code out the door as fast as possible and earn wads of cash. If there are bugs, they'll charge the customer money to fix them. Getting code right is of no interest; getting code fast is what counts. Haskell is a language that rewards those who sit back and deeply analyse the problem, and then produce a beautiful solution. Most companies don't care for this approach; let's just hack something together as fast as possible, and worry about fixing it later (i.e., never).

There are a few places where correctness matters. These are either safety-critical systems, or financial systems, generally. I gather Haskell tends to be quite popular here.

One final pair of data points:

  • I can still remember not so long ago hearing people cry "C++ is a toy language for n00bs! You should use a proper programming language like C." Now take a look around you and see how many large-scale C++ programs there are.
  • People have been claiming that Lisp is "the next big thing" for, what, 40 years now? Lisp is older than almost every programming language in mainstream use. And now many large-scale Lisp programs are there?

Which fate awaits Haskell, I don't know. I rather suspect all the good ideas of Haskell will be stolen by the likes of C# and hybrids like F# or OCaml,and people still won't ever use Haskell itself. It's just too different.

But anyway, as to why industry doesn't use Haskell, see the points above. It's too rare, too unpopular, too weird, and has incomplete libraries. That's basically it, in a nutshell.

Embedding Haskell?

The missing item for me is how hard it is to embed. For my purposes, I need to embed Haskell within an existing C++ framework, not dissimilar to how you might embed Lua. I need to do so in a compiler agnostic manner, where I retain control over how the embedding occurs (i.e. compilation and linking) and have significant influence over the operation of the runtime. In short, Haskell must fit in to my existing C++ environment, not the other way round.

An interesting aspect of an "Embedded Haskell" would be you could remove most (if not all) of Haskell's IO support if it made the job of embedding Haskell significantly easier. The ability to efficiently embed 'pure' Haskell would be a very interesting and useful tool in it's own right 1. It's a simple idea, and therefore doesn't take many words to state, but I'm keen to not understate how significant this could be.

Incremental adoption

Playing the counter argument, it could be argued that my needs are rather domain specific and an Embedded Haskell is not likely to be important enough to aid mainstream adoption of Haskell. This attitude does appear to be reflected in some parts of the Haskell community.

To start anecdotally, when I hear people propose writing something in Haskell, they generally imply the only option on the table is to write it in Haskell wholesale. Most arguments about use of Haskell I have read online focus on this either-or situation. For nearly all the reasons made in the quote above, this polarised position doesn't appeal unless you have very tailored circumstances and considerable resources.

There is also evidence of a lack of emphasis at a more fundamental level. GHC and the tools and libraries ecosystem that surround it are not designed with embedding as a goal. GHC is primarily focused on producing stand alone executables, which it does very well. Interoperability tools like Greencard immediately sideline the ability to call Haskell from C as having "little demand". Most emphasis is placed on wrapping C libraries for use in Haskell. The best I can find online are some open student projects such as the ageing GSoC ticket #1555, or the Embedded Haskell thesis topic in the PLS group. I believe this situation might be starting to change though, as the desire to remove the implementation obstacles surrounding much of Haskell's inspiring research builds, and new developments such as the LLVM backend present additional options.

Wholesale adoption of Haskell is undeniably risky and definitely not the only way. Incremental adoption is where it's at, and in a nutshell, that's what Haskell is currently missing the most.

  1. As an interesting historical aside, when Haskell first took up its purity banner, monadic IO did not exist and Haskell programs were pure functions of type [Response] -> [Request], where these types provided a limited set of options such as ReadFile, WriteFile, RequestFailed, ReadSucceeded for the side-effecting wrapper program to interpret. (See the Awkward Squad tutorial for further details.) Generalise this to a pure iteratee and you are probably in the right ballpark. []

Trackbacks & Pingbacks

  1. There are a hell of a lot of Haskell libraries now. What are we going to do about it? « Control.Monad.Writer pingbacked Posted 31 May, 2010, 5:02 pm

Comments

  1. Quote
    Lennart Augustsson said 30 May, 2010, 6:35 pm:

    Haskell programs have never been of type String->String. Perhaps you meant Response->Request?

  2. Quote

    As I commented on the post, the breadth of libraries isn't an issue, in my view. In fact, while Orphi asserts:

    > If you want to connect to an RPC server and fire off a few procedure calls… good luck with that. Same deal for talking to databases, accessing OS resources, manipulating binary file formats… You’ll basically have to write everything yourself from scratch. This is a big deal for commercial work.

    We actually have more than 2000 libraries on Hackage,

    http://hackage.haskell.org/packages/archive/pkg-list.html

    Including half a dozen RPC libraries, more than 50 database components, including all major server and cloud databases, and hundreds of "system" libraries.

    I'm really struggling to see library breadth as a problem.

  3. Quote

    I disagree with point 8. Performance in Haskell is no less predictable than
    in any other enterprise class language when in the hands of a programmer
    who is really thinking in Haskell. The real issue is 3 again - it's different.

    When the performance needs are moderate, a native Haskell speaker
    will instinctively avoid the kinds of constructs which tend to cause space
    leaks and performance sinks. If such problems do occur, it won't be
    harder to recognize where they crept in than in any other language.

    When performance needs are heavy, there is a well-stocked optimization
    toolbox. Using it may require some trial and error like in any language,
    but no unusually wild guesswork is needed.

    But a Java or C++ programmer who is valiantly trying to write
    idiomatic-sounding Haskell may indeed find that certain small changes
    in the code cause what seem to be magical effects, for better or
    for worse, in performance. Just as a hypothetical Haskell programmer
    who has never heard of imperative languages before would make the
    same observation about Java and C++.

    And that, of course, leads back to 6, and the false perception of 4.

  4. Quote

    @lennart Thanks for that, I've fixed the footnote.

    @dons I can't really speak on behalf of the original author, but the RPC example aside, I thought his point was essentially that we have Quantity (i.e. breadth), but not the Quality? I'm not sure how fair the "Outside World" point is - I have had problems along this line but mainly due to the Windows issue.

    @Yitz Fair point. I'm not really sure it's cut and dry either way. I don't think the situation is the same as imperative languages such as C/C#/etc though:

    On the one hand Haskell does far more aggressive program transformations than, say, a C++ compiler will do. This is a bit of double edge sword - I want this power as it's one of the major benefits of a pure functional language, but it does increase the amount I need to learn. Haskell in GHC is even more unique in that we can specify our own code rewrite rules. This is very cool, and although it's not as if I can ignore the implications of this, it's still a major plus in my book. I guess it's another way of saying powerful tools are powerful :).

    On the other hand, when we get it wrong and introduce, say, a space leak, the difference in performance you can get can be pretty staggering. Space leaks in particular can be really quite a pain in the ass. There's a fairly regular stream of posts on the cafe from people asking for help figuring out what's up with their code.

  5. Quote

    @Sam Martin "There’s a fairly regular stream of posts on the cafe
    from people asking for help figuring out what’s up with their code."

    If you look at those more closely, they often follow a pattern.
    These posts tend to be from experienced and successful
    imperative programmers with a fair amount of hubris, sometimes
    well-deserved and sometimes not. They expect to conquer the
    entire Haskell community within days, as they have done in other
    languages, so they jump right in to some very ambitious project.

    When they soon find themselves in much deeper waters than
    they bargained for, the reactions vary. The easiest reaction,
    especially for someone with hubris, is to blame the language.
    A few were so psychologically scarred that they became
    pathological anti-Haskell trolls to this day. Others are capable
    of realizing that Haskell is just different - they go on to be
    enriched by the experience, whether they continue with Haskell
    or not.

    Aside from the above scenario, the next most common kind
    of post about performance issues is in cases where the
    underlying problem is difficult. These issues will of course be
    more or less the same in any language.

    Finally, you are left with actual language design issues relating
    to performance. Decades ago, when functional programming was
    new, there were common cases that were difficult performance
    problems in functional languages while trivial in imperative languages.
    Those issues have long been settled. Now the constant process of
    gradually increasing performance looks about the same in Haskell
    as in any other mature language - though a pure functional language
    does seem to have a decided advantage for emerging platforms.

    Then there is the theoretical side. Again, decades ago it was
    sometimes difficult to state and prove results relating to
    performance in pure functional languages, because much of the
    existing literature was formulated in strongly imperative
    language. Now much progress has been made, but there are
    still open research questions. I'll leave the literature review to
    the academics among us.

    In general, whenever the trolls start piling up "proofs" that
    performance is an inherently difficult problem in Haskell, trace
    back the actual sources. You'll find that in each case, either
    the person complaining of performance problems is
    an inexperienced Haskell programmer, or the source is at
    least a decade old.

    Ultimately, the myth that there are inherent performance problems
    with pure functional languages stems from the fact that they are
    indeed quite different from imperative languages. I think it is
    important to debunk that myth.

  6. Quote

    @Yitz: Please start by writing a performant generic sort in Haskell.

  7. Quote
    MichaelWH said 9 June, 2010, 12:06 am:

    @Yitz

    "I disagree with point 8. Performance in Haskell is no less predictable than
    in any other enterprise class language when in the hands of a programmer
    who is really thinking in Haskell. The real issue is 3 again – it’s different."

    How well is Darcs doing on containing sudden, unexpected, time- and space-consumption combinatorical explosions again? Oh, right. The Darcs people are just not thinking in Haskell....

  8. Quote

    The truth about Darcs performance is hard for me to convey in a snark-proof soundbite of less than 140 characters.

    My latest attempt at boiling it down is to say that Darcs performance is about three things: (i) theory, (ii) engineering and (iii) implementation.

    Theory means the core theory of patches which makes Darcs powerful and easy to use... until you hit a conflict. Simple conflicts are fine. When conflicts nest, however, you do get a combinatorial explosion of nested "merger" or "conflictor" patches. The darcs-2 version of patch theory obviates a lot of this nesting, but we still have a lot of work to do on the theory end. Haskell is irrelevant here.

    Engineering refers to high-level choices about how we store information and ship it around. Darcs performance has been improving a lot in the last two years because we have been emphasising the engineering aspect of things. For example, we use timestamps to determine if we need to check the committed and working copy of a file for differences; however, because we also use hard-links to save time/space, the timestamps from the filesystem can mislead Darcs into checking for way more differences than it needs to. Recent versions of Darcs use an index file to store our own timestamps. Another example of work we are doing in this line is to "pack" our many small files into fewer larger files that we can transfer over HTTP a lot more quickly.

    Implementation can include choices like Haskell as a programming language. The last time I tried to clarify this, I said that Haskell doesn't make a difference here. Thinking more about it, I realise I was likely wrong. Sorry! One place where Haskell *could* make a difference is that we have a number of performance bugs we have open where Darcs seems to be using an unreasonable amount of memory for the task at hand. It's not yet clear to me if these are actually engineering bugs in disguise, or if some of them are not merely implementation details. The Darcs team is quite small; we need all the help we can get. Once we've reached a couple of engineering milestones we have in mind, it'd be really great if the wider Haskell community could give us a hand on understanding these bugs.

    Meanwhile, I still have the conviction that solving a lot of the engineering issues (Darcs 2.5 and 2.6 look very promising) will make Darcs a lot faster for most people, most of the time. We still need to work on theory and implementation over time, but I hope you'll like what we've accomplished for the short term.

  9. Quote
  10. Quote
    Greg Graham said 1 August, 2010, 8:20 pm:

    Did people say "n00b" back when C++ came out? I don't remember hearing it then, or at least seeing it spelled with zeros. ;)

  11. Quote

    OO is popular for modeling domains, and for better or worse, OO design is entrenched in industry, and isn't going away.

    Are FP and OO fundamentally incompatible? If Haskell's type system is so superior, how does one actually make the transition from an OO mindset, and how does one approach complex domain modeling problems in Haskell? Where are the case studies in how this benefits industry? I still haven't seen this addressed from the Haskell community... though I have seen lots of academically interesting concepts come out of it.

  12. Quote

    Embedding is certainly possible. I'm doing it with Hubris, and the Haskell FFI is a joy to work with in that direction too. It's not emphasised, for some reason - I think most Haskellers expect Haskell to be on top of the stack, but using Haskell with a loose binding language like Ruby seems eminently sensible to me.

  13. Quote

    3,4. Yes, Haskell is different.

    4. When I for one whip out the "monad is a monoid in the category of endofunctors" comment, it is mostly with my tongue firmly in my cheek, unless I'm talking to someone else who has spent a lot of time fiddling with category theory. My blog is filled with particularly egregious examples of this sort, but I make no claims that it is a gentle introduction, merely a smattering of things I want to talk about.

    6. I have never had difficulty meeting my demand for Haskell programmers and the ones I have hired have been among my best employees.

    7. Talking to an (XML-) RPC server: http://www.haskell.org/haxr/ There are also several others.

    7. Lack of windows support: yes this is definitely a big deal. In the Haskell community's case, there just isn't much of a user base there building things. Yes, this goes back to your previously mentioned recursion principle, but sadly, it is an artifact of the current user base. The Platform, however, builds on Windows and is growing to encompass more and more of the core functionality you would expect out of a language with 'batteries included'.

    8. Isn't a problem if you take the time to grok strictness annotations and explicitly unpack structures that will obviously be used with high frequency. These will help address space leaks, which cover the worst performance issues.

    w.r.t. Embedding: The old [Request] -> [Response] driver was an 'initial algebraic encoding' of the problem. On the other hand, IO is 'final'. They are equivalent systems. You're mistaking arguable issues with there being too many assumed trappings in the existing platform for embedded systems work for the mechanism used to implement those trappings. If you're turning to an ADT to express a language you're probably using the wrong tool (See "Finally Tagless, Partially Evaluated").

    As to your overall conclusion? I happen to disagree, but wanted to stick to quantifiable issues.

  14. Quote

    Maybe this is obvious, but it's worth noting:

    If it's merely just as productive as what people are already familiar with, or pretty close to it, there's no reason to switch.

  15. Quote
    Karsten Wagner said 3 August, 2010, 7:06 am:

    An important point missing: Syntax. Ideomatic Hakell-Code often looks like line-noise. In other words: Haskell has the worst looking code since Perl.

    While this seems superficial, it´s quite important in the industry. Guess why Cobol had the syntax it has and why Javas "elaborate" syntax is considered a feature. Naming stuff is better than using strange symbols if big teams work on big code-bases - thats the main reason Java still hasn´t operator overloading.

    Haskell has been designed as a language for programming-language-reseach. In this area free definable operators are a good thing because it allows to try out interesting things without having to change the parser of the compiler. But for industrial use, it´s a very dangerous feature.

  16. Quote

    About syntax: operator overloading is always controversial, but Guy Steele clearly stated he wanted it for Java, in his talk "Growing a Language".
    But yes, there are cases where overloads are not so natural, and a name should be provided (to be used as an operator possibly). But that is mostly about the second issue - completeness of existing libraries.
    I'm still a learner of Haskell, but I happened to find many half-finished projects for Haskell, or having only partial documentation.

  17. Quote
    Alexander Solla said 11 February, 2011, 5:09 pm:

    I just ignore the "line noise". Line noise is nearly always glue code. I don't want that named. I just want it done. Yes, it can be hard to write from scratch. But any sane Haskell development environment uses an interactive environment like GHCi. If you use the type checker to guide you, writing the glue becomes trivial. Encode logic in data types, and let the glue write itself. If glue code type checks, it works, guaranteed. These are free theorems. Focus on the important things: the stuff you're gluing together.

    And often, there is no natural name for a function that traverses multiple control structures. The denotation is the most informative name. What would you name a function that lifts a function into two nested functors, is partially applied, and is then lifted up into another functor? This kind of stuff happens quite a bit. And my code is easy to read, because nearly invisible glue code connects two concepts in a relationship that makes sense (typically in terms of products or direct sums implemented via functors).

    Consider the expression: (num_shirts_in_factory_a + num_shirts_in_factory_b). Which parts of that expression are the informative ones? Obviously, it is the "num_shirts" variables. And there is only one "sensible" way to put those quantities together. Now push this idea to its limit. It is more than there just being one sensible way to write glue. There is exactly one glue function between glue-able types.

    On the other hand, I have used some type classes to move some of the more repetitive glue away. I have classes like:

    class Monic a b where inject :: a -> b -- to represent monic morphisms
    class Epic a b where surject :: a -> b -- to represent epic morphisms

    You can easily have a class like

    class Glue a b where
    glue :: a -> b

    and hide all the line noise in there. And then your client code will look like

    blah :: StateT (MaybeT IO) (Integer) (Maybe Integer)
    blah = glue . parseInt . glue . getLine
    -- or
    blah = glue $ parseInt $ glue $ getLine

    This is how "line noise" glue code looks to me. Except line noise is more maintainable. *fnord* Note that these glue functions would each require their own distinct type class instance.

    The nicer the client code looks, the more complexity you have to shovel into the Glue instances. But you are merely transferring complexity -- not creating or destroying it. Complexity is created by data type definitions being glued. There is the potential for a combinatorial explosion, since you can have unused Glue instances, whereas you cannot have unused "line noise" glue code.

    Mathematicians don't care about mathematical symbols. They care about the things the symbols join, because the semantics of joining "things" is dependent on -- and usually determined by -- the things being joined.

  18. Quote

    What would you say if I, a startup owner, used haskell for some of my graph algorithms? Crazy? A lil' bit. But I'm gonna do it. Can't stop an enthusiast. My upper-div prog languages course in CS inspired me and now I can't stop ;D

  19. Quote

    "C++ is a toy language for n00bs! You should use a proper programming language like C."
    This could be only said by bad programmers that doesn't understand programming languages.

  20. Quote

    @Jon Harrop: In spite of being popular with Haskell textbook writers: quicksort isn't the best algorithm to use on Haskell lists. Bottom up mergesort is.

    > mergeSortBy :: (t -> t -> Ordering) -> [t] -> [t]
    > mergeSortBy comparator = head . mergeall . split where
    > split [] = []
    > split (a:r) = [a]:(split r)
    > mergeall [] = []
    > mergeall [x] = [x]
    > mergeall s = mergeall $ mergePairs s
    > mergePairs [] = []
    > mergePairs [x] = [x]
    > mergePairs (a:b:r) = (merge a b):(mergePairs r)
    > merge [] b = b
    > merge a [] = a
    > merge (a:ar) (b:br) = if b `comparator` a == LT then
    > b:(merge (a:ar) br) else
    > a:(merge ar (b:br))
    > mergeSort :: (Ord a) => [a] -> [a]
    > mergeSort = mergeSortBy compare

  21. Quote

    Damn: I'd hoped using literate haskell would have caused the whitespace to be preserved

  22. Quote

    Sorry I'm afraid the blogging software isn't that clever! Thankfully it's still readable. :)

  23. Quote
    SeanVN said 7 April, 2014, 6:55 pm:

    Puke! I'm not learning completely different syntax and way of doing things. If I have to learn another language I want to reuse my existing knowledge of C/Java etc. Actually I am starting to get quite old. I am finding it a lot easier to continue programming in lower level languages such a C and assembly language. I definitely don't get a kick out of higher level languages these days. Also there are too many Smart Alex who will use the features of a high level languages to produce extremely obfuscated code. This proves how clever and indispensable they are. If I ran a software company I would maybe even choose to program everything in like Basic so that if someone left it would be possible to maintain the code they left behind.

Leave a Comment

(required)

(required)

Formatting Your Comment

The following XHTML tags are available for use:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

URLs are automatically converted to hyperlinks.