top | item 5893442

Ask HN: Any downsides of programming in Haskell?

50 points| raphinou | 12 years ago | reply

To anyone who developed a real world application in Haskell, what are the downsides of it?

What is in your opinion more laborious than needed? Are library sufficiently available and documented? Is doing I/O fine? Is working with a DB easy? Please share with people interested in learning Haskell and put it to work in a real world application!

PS: asking for negatives only because I'm very interested and positive about Haskell, but I wonder if I miss some gotchas...

72 comments

order
[+] sseveran|12 years ago|reply
Most of the issues mentioned so far are trivial or just warts. The real issue is understanding the design patterns that work well enough to build high performance applications. Also in order to really exploit the power and productivity of Haskell there is quite a learning curve.

We built an algorithmic trading system, and almost everything else in Haskell. Our code base is over 100K of human written code.

The major library gaps were a time library (you can find a version of what we have been thinking about releasing at https://github.com/time-cube/time-cube). We use our own build system that drives cabal and ghc. Otherwise having many libraries is just painful.

We found that composing applications as conduits to be a very effective design pattern that minimizes many laziness issues. Monad transformers are very powerful but the machinery for them (like forking) is not fully cooked.

Maintaining the codebase is far easier with haskell than with anything else I have worked with (C/C++,C#,Java,etc...). Refactoring in Haskell is great.

You can't fight the language. Fighting with Haskell will cause great pain. When you go with the flow, using lots of strong types, higher order functions and can apply things like a monoid instance to a problem the language is a joy to work with.

Debugging is more painful than it has to be. There are still times when you need some real GDB wizardry.

Lastly if you have more questions feel free to contact me through our website http://www.alphaheavy.com

[+] carterschonwald|12 years ago|reply
I strongly recommend folks take Steve up on his offer, they (alphaheavy) do really neat engineering and they're incredibly knowledgable.
[+] mooism2|12 years ago|reply
Haskell's record system (analogue of C's structs) has two major deficiencies.

1. Modifying a record value (that is, making a copy of a record value but with different values in one or two of its fields) is unnecessarily complicated and uncomposable. This makes modifying a subfield painful.

2. Field names are in the global namespace. Thus you cannot have e.g. a field named `map` (conflicts with the standard `map` function); nor a local variable named `owner` in the same scope that you use a field named `owner`; nor may two different record types both have a `name` field. C had this problem in the 70s (which is why e.g. struct tm has tm_sec and tm_min fields instead of sec and min fields), but they solved it a long time ago.

The solution to deficiency 1 is to use lenses. Use the lens package from Hackage, but don't read its documentation at first: it generalises the problem exceedingly well, but this makes it harder to understand at first glance. Instead seek out a basic tutorial. At the cost of a short line of boilerplate for each record type, this works well.

There is no satisfactory solution to deficiency 2. Some people define each record type in its own module, and import each module qualified. I don't think this scales well. I prefer to put a record-type prefix on each of my field names (i.e. the same thing C programmers were forced to do in the 70s).

[+] pestaa|12 years ago|reply
Both are true, but I consider the second problem to be more like a trade off. In PHP I miss field extraction from an array so often; in Haskell it is just `map fieldName` and voila. Works just as well with namespaces -- I understand it does not scale when creating data types, but you normally don't import all of them at the same time into another module anyways.
[+] tcsavage|12 years ago|reply
There's currently a Google summer of code project implementing overloaded record fields (http://www.google-melange.com/gsoc/project/google/gsoc2013/a...) - which should kinda solve problem 2. You still wouldn't be able to define a field `map` for the same reasons you stated, but you would be able to have multiple record types sharing the same field names.
[+] LukeHoersten|12 years ago|reply
In my opinion the module system (http://www.haskell.org/onlinereport/modules.html) is a bit weak. For example: "It is not possible, however, to hide instance declarations in the Prelude. For example, one cannot define a new instance for Show Char."

Instances can't be explicitly imported either.

Another thing I don't like is if you have two different functions with the same signature but different implementations meant to give swappable functionality, there's no way of specifying that explicitly. As a user of a library, you just have to realize the functions can be swapped out with modules. For example:

http://hackage.haskell.org/packages/archive/bytestring/0.10....

http://hackage.haskell.org/packages/archive/bytestring/0.10....

It's really not that bad but I do like how other languages allow the programmer to make this explicit.

[+] ekmett|12 years ago|reply
When given the ability to qualify the instances you import you lose confluence of instance resolution. This is BAD.

We rely on confluence to enable us to move class constraints to where they are used rather than have to carry them around in every object.

Scala tries to get away with having the ability to explicitly pass dictionaries around and the result is frankly a muddled mess. Monad transformers wind up nigh unusable, sets can't use efficient hedge merges, etc.

Explicitly enumerating instance imports is one of those things that seems like a good idea until you actually explore its consequences.

I can't defend the ByteString API on the other hand. ;)

That said, I do not find it particularly "Haskelly".

[+] sparkie|12 years ago|reply
> Another thing I don't like is if you have two different functions with the same signature but different implementations meant to give swappable functionality, there's no way of specifying that explicitly. As a user of a library, you just have to realize the functions can be swapped out with modules.

Haskell is possibly better in this regard than many other languages, as you can make existing functions become polymorphic without modifying them. (say for example, in most OOP languages, you would need to add an additional interface to each class where you want to use a method interchangeably, which you can't always do.)

In hask, you can just create a new typeclass for the particular functions you want to be swappable, and add an instance definition for each.

eg, http://pastebin.com/9RVMZyz1

[+] ac|12 years ago|reply
> Instances can't be explicitly imported either.

You can import only instances by saying "import A.B.C.Instances ()" where A.B.C.Instances is the name of the module where the instances are defined.

[+] stepcut|12 years ago|reply
For me, the biggest downside is lack of solid embedded device support -- arduino (Atmel AVR), android(ARM), iOS (ARM).

After using Haskell pretty much full-time for 10 years, writing C and Java code makes me sad. The support for the above mentioned platforms is in-progress, but is not yet mature.

There are some neat things like Atom which use a Haskell DSL to target arduino.

My other issue is that the garbage collector in GHC is not really sufficient for real-time audio applications because it can pause for too long. GHC HQ has tried to tackle this in the past -- but there is a reason why it is a research topic :)

If your application requires interfacing to a C++ world -- your are not going to have fun. Though there might be a GSoC project for that this summer?

Also, GUI stuff is somewhat lackluster. There are bindings to gtk, etc. And they can get the job done. But they don't really capture the essence of what makes Haskell awesome. We are still searching for the GUI abstraction that really clicks.

[+] gruseom|12 years ago|reply
After using Haskell pretty much full-time for 10 years

Wow! Doing what?

[+] ac|12 years ago|reply
Depends on what you are doing. The library eco-system used to be a weak link in Haskell, but I see it improving. To clarify, there were (and still are) a lot of broken and/or poorly documented and/or unmaintained libraries on Hackage. Or several libraries for doing the same thing where there is no indication of which library is the best choice. I suspect that is, to some degree, the case in any open-source eco-system, thought. Recently, though, thanks to the effort of the giants like Edward Kmett there have been an influx of great well-documented libraries on Hackage. And of course, you are welcome to contribute new packages/improvements to existing packages.

Working with DBs is easy, especially if you use HaskellDB. There are bindings for non-relational DBs, as well as a DB written in Haskell (acid-state).

As for the language itself, you might find it tricky to develop computation intensive applications with large run-time data-sets due to garbage collection (but that is true for any garbage collected language). Other than that, it's one of the best performing languages in the Debian PL shootout. And the fact that concurrency is (comparatively) easy means you can make use of those extra cores.

Monad transformers and monads are fine, you just need to learn how to use them.

To sum up: it depends on what you do and what you consider a "real world application". Might be a good idea to elaborate. For example, are compilers, games, web apps, automated trading systems, android apps considered "real world"? Because any of these has been done in Haskell.

[+] raphinou|12 years ago|reply
I mentioned real world app to mean "not a toy project". That is, i meant a reasonably large, structured, maintainable code base. I am thinking of haskell as the language to use for a new project, and am interested to know more about the potential problems and downsides i should be aware of. Also are there situations where one should absolutely avoid haskell?
[+] jamwt|12 years ago|reply
The runtime is somewhat immature. It locks up oddly sometimes under heavy load. Dealing with latency and queuing issues around gc pauses is much less understood/documented than in the JVM world. The set of best practices in general for doing intense things with the ghc runtime is just still young and sparse.

STM can exhibit something that looks a hell of a lot like livelock.

Error handling is brutal. Catching all classes of exceptions (at the place you want to catch them!) for recovery is surprisingly tricky. This isn't necessary in theory with things like MaybeT, but in practice, lots of odd libraries use things like partial functions and the error function.

Not having tracebacks in production code is painful

The library community is thriving but it has a lot of volatility. Things break each other quite frequently. Semantic versioning either isn't enough to save it or hasn't been adhered to strictly enough.

Thunk leaks and other consequences of unexpected laziness aren't as common as people worry about, but they're kind of a pain to track down when they occur

Strict vs. Lazy bytestrings, String, Text, utf8-string, etc. You may find yourself doing a lot of string/bytestring type conversion

There's still wars raging about the right way to do efficient, safe I/O streams. Conduit vs. Enumerator vs. Pipes etc. They're all turning into pretty compelling projects, but the fact that there are N instead of 1 is sometimes a drag when you're dealing with libraries and dependencies.

There are not a lot of good open source "application server" type frameworks that really handle thread pooling, resource exhaustion, locking, logging, etc, in robust nice ways. We have one internally, and I'm sure a bunch of other haskell-using shops do too, but the ones on hackage are not nearly sophisticated enough (IMO) and I suspect not very battle tested against the kinds of ugly queuing problems you run into in highly loaded environments.

If I think of more, I'll add em... these are off the top of my head.

[+] tome|12 years ago|reply
> lots of odd libraries use things like partial functions and the error function.

This is very naughty and I hate it.

[+] dons|12 years ago|reply
> It locks up oddly sometimes under heavy load.

???

[+] Peaker|12 years ago|reply
Runtime debugging in Haskell is more rare, but when you need it, it's more of a headache.

Achieving performance is harder than in c or c++.

The ecosystem is strong on some counts and weak in others.

There's lots of API duplication (lazy/strict byte strings, map, set, seq, etc).

Good performance may depend on brittle ghc optimizations that might break in very difficult to comprehend ways if ghc is upgraded.

[+] jhickner|12 years ago|reply
We wrote our RF radio mesh coordinator software in Haskell, and it's been a great success. Working with binary data formats (various building control protocols) in Haskell is the kind of thing that spoils you forever.

The one issue I've run into is that ghc can't cross compile. If you want to run your code on ARM, you have to compile an ARM version of ghc (QEMU comes in handy here).

[+] carterschonwald|12 years ago|reply
much better cross compilation support will be landing in ghc 7.8
[+] bjourne|12 years ago|reply
Let's begin by stating that Haskell is great, but there are a lot of stuff I don't like about it:

1. Way to many user defined operators. Haskell lets you define almost anything as an infix operator which library authors love to (ab)use. So you get operators like ".&&&." (without the quotes) because they are functions reminiscent of the boolean and operation.

2. But weirdly enough, many operators aren't generic. String concatenation is performed with "++" but addition with "+".

3. Incomplete and inconsistent prelude. It has unwords and words for splitting and joining a string on whitespace. But you dont get to specify what string to use as the delimiter like the join and split functions in other languages lets you do.

4. So instead you have X number of implementations of splitStringWith on Hackage, some of which are unmaintained, deprecated or just not working, meaning that just answering the question "how should I split a string?" becomes a big endeavour (http://stackoverflow.com/questions/4978578/how-to-split-a-st...).

5. There are four different "stringish" types in Haskell: List, LazyList, ByteString, LazyByteString. A function like splitStringWith works on one of the types, but not the three others for which you need other functions. Some libraries expect Lists, other ByteStrings or LazyByteStrings so you have to keep converting your string to the different types.

6. Most Haskellers seem to content with just having type declarations as the api documentation. That's not a fault of Haskell per se, but imho a weakness in the Haskell community. For example, here is the documentation for the Data.Foldable module: http://hackage.haskell.org/p ackages/archive/base/latest/doc/html/Data-Foldable.html

7. This is very subjective and anecdotal but I've found the Haskell people to be less helpful to newbies than other programming groups.

[+] tome|12 years ago|reply
> 5. There are four different "stringish" types in Haskell: List, LazyList, ByteString, LazyByteString. A function like splitStringWith works on one of the types, but not the three others for which you need other functions. Some libraries expect Lists, other ByteStrings or LazyByteStrings so you have to keep converting your string to the different types.

I guess you mean String, ByteString, Lazy ByteString, Text, Lazy Text?

> 6. Most Haskellers seem to content with just having type declarations as the api documentation. That's not a fault of Haskell per se, but imho a weakness in the Haskell community. For example, here is the documentation for the Data.Foldable module: http://hackage.haskell.org/p ackages/archive/base/latest/doc/html/Data-Foldable.html

But there's more documentation than just type signatures on that page! Anyway, being able to rely on type signatures as documentation is testament to the expressivity of the type system, encourages small reusable combinators, and is a great strength, in my opinion.

> 7. This is very subjective and anecdotal but I've found the Haskell people to be less helpful to newbies than other programming groups.

Strange, I've always heard they're one of the communities most helpful to newbies. I don't have any evidence one way or other though.

[+] koomi|12 years ago|reply
Regarding 4, the split package[1] is the widely accepted standard for splitting lists in various ways and you will likely already have it installed since quite a few packages (142 to be exact) depend on it.

Regarding 5, I have never heard of LazyLists, nor can I find them on Hackage, nor does that name make any sense since normal (:,[]) lists are already as lazy as it gets. (Lazy) ByteStrings are, as the name indicates, more for raw binary data, but can also be used for text . The modern standard for strings is Text[2]. The OverloadedStrings extension makes it considerably easier to work with literals of the differnt string-like types.

Regarding 6, I find documentation in Hackage packages quite good. Your example, Foldable, not only has a decent explanation of each function in the typeclass definition, but there are also good tutorials (e.g. Typeclassopedia[3]) since it is definitely a non-trivial typeclass.

[1] http://hackage.haskell.org/package/split [2] http://hackage.haskell.org/package/text [3] http://www.haskell.org/haskellwiki/Typeclassopedia#Foldable

[+] spyked|12 years ago|reply
> 2. But weirdly enough, many operators aren't generic. String concatenation is performed with "++" but addition with "+".

Some see concatenation as addition, others as composition. Funnily enough, in Haskell addition is reserved to numbers and composition to functions. I'm guessing that's why "(++)" was chosen for lists, with strings as a particular case.

[+] Dewie|12 years ago|reply
> 2. But weirdly enough, many operators aren't generic. String concatenation is performed with "++" but addition with "+".

Concatenation and addition don't share the same algebraic properties (concatenation is not commutative). Haskell has a mathy bias (for example see the monoid typeclass, which I guess you can use if you want to use the same operator for concatenation and for addition) so this choice isn't very surprising.

Besides, it seems like Haskell chooses to have more specialized functions/operators in Prelude while their generalizations are reserved for other modules. For example "map" for lists, "composition" (.) for functions, but "fmap" for functors in general.

[+] papsosouid|12 years ago|reply
1. What library are you complaining about? Haskell has a pretty small, well established set of operators. If a library is defining more operators than you like, then don't use it. That is no different than a library defining functions with names you don't like, it happens in every language.

2. Why on earth would string concatenation be the same operator as addition? That isn't the same operation. I want to know if I used + that I have to have gotten a number, or else it won't compile. Getting a string would be very unhelpful. If you just want any monoid, then there is a generic operator for that, it is <> or mappend.

5. The different types are for different purposes. String is a list of chars. You use normal list functions on it. Bytestring is not a string, it is an efficient container for storing bytes. It is used for things like networking. Text is an encoding aware, efficient representation of strings. Use this for text data. There is an IsString typeclass for generic functions that operate on any type that can behave like a string.

7. I've always heard the exact opposite from everyone, and my experience has also been the opposite of yours. The only other computer related community I have seen that is as helpful as haskell is postgresql.

[+] ciderpunx|12 years ago|reply
I found it a lot slower than more imperitive style languages. I've been writing in c-like languages for something like 30 years, so I suppose that's not unexpected. I found that the type system sometimes got in my way. And combining monads (even with monad transformers) was also a faff. In the end I suppose it depends what you're trying to make. I think Haskell is great for DSL applications and less so for things like web dev. Though that being said Yesod is a pretty nice framework.
[+] belovedeagle|12 years ago|reply
The thing is, if you feel like the type system is "getting in your way" you have to step back and ask, "do I really understand what I'm achieving here?" Of course, it's very easy to feel like you know what you want and you can't figure out the types for it, but you have to realize, if the type check fails then what you asked for just doesn't make sense, like adding an Int to an (IO Int).

The whole point of the type system is that it substitutes compile-time errors (that are admittedly esoteric) for obscure run-time bugs that might not even ever show up except on that one person's machine and use-case.

But yeah, it's never fun to see a screenful of type errors.

[+] chrisdone|12 years ago|reply
As a professional web dev having used Haskell for four-five years, I wouldn't want to do web dev in anything else. The static guarantees are too great. Throwing them away is literally asking for bugs.
[+] carterschonwald|12 years ago|reply
Honestly I think the biggest down side is that there's not enough commercial endeavors using Haskell, and thus theres horrifyingly few people working full time on many core pieces of the ecosystem. Yes, my biggest critique is that all the great stuff in the Haskell ecosystem is the result of a small collection of smart folks helping out in their spare time.

It makes me wondering what magic would happen when those folks can work on helping the ecosystem full time!

I have to say that one of my favorite things currently about haskell is how nice and easy the c ffi is to use. So darn simple! (I'm also GSOC mentoring some work to provide a nice C++ ffi tool too).

Theres so many great tools in the Haskell ecosystem, for every problem domain. Its not perfect, and theres always room for more improvement, but those improvements are happening, and the more people invest in supporting the community, the more those improvements happen!

For example, one thing i'll be exploring in the neat future is how to do good Numa locality aware scheduling of parallel computation. It looks like i might be able to safely hack support in via a user land scheduler (though i'll find out once i get there).

My principal work right now is building numerical computing / data analysis tools, and some of the things I'm doing now would be simply intractable in another language.

[+] mynameisme|12 years ago|reply
Cabal and friends are awful compared to Bundler/Maven/etc.,even with the various wrappers available. Also, the tooling isn't that great compared to Scala or F#.
[+] ppereira|12 years ago|reply
Monad transformer hell.
[+] raphinou|12 years ago|reply
Can you share a bit more? I'm not familiar with Monad transformers.
[+] papsosouid|12 years ago|reply
Records are annoying, but can be worked around. The compiler is incredibly slow and uses tons of RAM (I need 2GB to compile my simple little web app for example). The slow compile times can start to really kill productivity on large projects. The web frameworks are all pretty focused on trying to reproduce industry worst practices rather than doing things right, so if you are doing web development and you don't want your app to be a mess, you are kinda on your own. That's pretty much it.

edit: to clarify on the web thing, when I say "on your own" I mean you won't be able to get much from existing tutorials and examples since you will want to do everything differently. Not that you will have to write your own framework.

[+] Ixiaus|12 years ago|reply
The only Haskell web application framework I feel is well-designed is Snapframework. My experiences with Yesod echo your sentiment and Happstack doesn't quite cut it. Scotty is too low-level (from my cursory investigation).

The compiler is slow, yes, but it is also doing a lot of work for you; the benefits of using Haskell outweigh the time to compile, for me personally.

[+] mightybyte|12 years ago|reply
I'm interested in hearing your thoughts on web development. Would love to chat on IRC...or maybe drop me an email if you're inclined.