
Ask HN: Any downsides of programming in Haskell? - raphinou
To anyone who developed a real world application in Haskell, what are the downsides of it?<p>What is in your opinion more laborious than needed? Are library sufficiently available and documented? Is doing I&#x2F;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!<p>PS: asking for negatives only because I&#x27;m very interested and positive about Haskell, but I wonder if I miss some gotchas...
======
sseveran
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](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](http://www.alphaheavy.com)

~~~
carterschonwald
I strongly recommend folks take Steve up on his offer, they (alphaheavy) do
really neat engineering and they're incredibly knowledgable.

------
mooism2
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
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.

~~~
dllthomas
That doesn't require them to be in the global namespace.

------
LukeHoersten
In my opinion the module system
([http://www.haskell.org/onlinereport/modules.html](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.2.0/doc/html/Data-
ByteString-Char8.html)

[http://hackage.haskell.org/packages/archive/bytestring/0.10....](http://hackage.haskell.org/packages/archive/bytestring/0.10.2.0/doc/html/Data-
ByteString-Lazy-Char8.html)

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

~~~
ac
> 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.

~~~
tome
But not individual instances.

------
stepcut
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
_After using Haskell pretty much full-time for 10 years_

Wow! Doing what?

------
ac
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
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?

~~~
ac
Yes, I think you should avoid Haskell (and any language with managed memory)
on embedded systems or in very performance critical applications. Beyond that,
it's going to be a choice of whether there are enough well-supported libraries
that help your cause versus some other language. It would help to know in what
domain is your new project is going to be.

You've mentioned web apps, so, to be specific, I think the Haskell web app
frameworks (Happstack, Yesod and Snap) are mature. There aren't nearly as many
utility libraries, as there are, say, for Rails. But that, in my opinion, is
compensated by greater correctness guarantees and performance.

I'd encourage you to join the haskell-cafe [1] mailing list: it's a great
place to get help if you get stuck.

[1] [http://www.haskell.org/mailman/listinfo/haskell-
cafe](http://www.haskell.org/mailman/listinfo/haskell-cafe)

~~~
DanWaterworth
> Yes, I think you should avoid Haskell (and any language with managed memory)
> on embedded systems or in very performance critical applications.

You're forgetting about atom,
[http://hackage.haskell.org/package/atom](http://hackage.haskell.org/package/atom).

------
jamwt
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
> lots of odd libraries use things like partial functions and the error
> function.

This is very naughty and I _hate_ it.

------
Peaker
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
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
much better cross compilation support will be landing in ghc 7.8

------
bjourne
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...](http://stackoverflow.com/questions/4978578/how-to-split-a-
string-in-haskell)).

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](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.

~~~
papsosouid
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.

~~~
bjourne
1\. HXT, Lens, Arrows.. etc. _I think_ (as in, this is my opinion, someone
else may think that the amount of operators they contain are reasonable) they
introduce way to many infix operators. They are also pretty important to the
Haskell eco-system, so you can't just choose alternatives with less "line-
noise."

2\. I think the question should be why on earth should they not use the same
operator symbol? In most other mainstream languages they are. I know the
answer is "because [Char] isn't part of the Number typeclass" but that misses
the point.

5\. Both Text.Regex and the split library someone else mentioned operators on
strings ([Char]). Data.Aeson uses ByteStrings. So not everything in Haskell-
land uses Text when they should which leads to lots of annoying string packing
and unpacking. Contrast this with Python (3) where you have (unicode) strings
and (byte) buffers. Only. If you want more efficiency there are 3rd party lazy
implementations of them, but they aren't forced upon you like in Haskell.

~~~
Ixiaus
1\. I don't think they define too many specialized operators personally;
Haskell's heritage is more "mathematical" than many other languages so it
makes sense that many variables are single letters and operators are defined
with symbols instead of _reallyLongAndDescriptiveName_. It's part of learning
the idioms of the language.

2\. They should _never_ use the same symbol. As the parent said, if you want
the generalized notion of a monoid then use that (<> or mappend), otherwise
each library should not be conflating its instance of a TypeClass with other
libraries' instances of a TypeClass - it is confusing and you end up with
stuff like:

    
    
        import Some.Lib as L
        import Some.Other.Lib as OL
        
        (L.+) 2 3
        (OL.+) "2" "3"
    

vs.

    
    
        import Data.Monoid
        
        (Sum 2) <> (Sum 3)
        "2" <> "3"
    

Which is inevitable for some libraries (Fay for example re-defines a lot of
Prelude functions) and sometimes accidental; but it is confusing and bad
design unless you define a way to generalize it (Monoids!).

5\. Data.Aeson uses ByteStrings for the JSON serialization, when
encoding/decoding you provide your own instance defining the Types (can be
Text/String/ByteString) so I don't understand your gripe here; Text.Regex
shouldn't be used for Data.Text, that's what this package is for:
[http://hackage.haskell.org/packages/archive/text-
icu/0.6.3.5...](http://hackage.haskell.org/packages/archive/text-
icu/0.6.3.5/doc/html/Data-Text-ICU-Regex.html)

~~~
bjourne
When you want to encode and decode JSON data of unknown format then you need
to use the encode and decode functions directly which operates on ByteStrings.
You really don't want to create a new record for each possible kind of JSON
data container you have.

text-icu is an experimental 3rd party binding and doesn't work like pcre
anyway. It's not something you would use over Haskell's standard library
regexp support, so you still have to deal with X number of different string
types.

~~~
Ixiaus
True re: encoding or decoding; but it does make sense to me to keep it in
ByteStrings as that is an efficient representation - from ByteStrings you can
do what you want with it (convert it to Text).

I personally haven't used the Text.ICU package but I know many, big, packages
that retain the "experimental" flag. So that shouldn't necessarily deter
usage; just because it's 3rd party doesn't mean it's bad either - many
fundamental components of the Haskell ecosystem are 3rd party! There are also
many libraries that implement bindings - I don't necessarily see why that is a
bad thing either; obviously a pure Haskell approach would be nice but in some
cases it does defeat the purpose to reinvent something.

What I do agree with you on, though, is the lack of clarity in _what_ should
be used. I think the Haskell Platform is a good start in that direction but
there are few docs written on "this is how you deal with strings and unicode
in Haskell and all the libraries we recommend for it".

The good news is, this language has the capability to serve both the research
needs of academics and the practical needs of implementers; so uncovering this
stuff is very good.

------
Silhouette
This discussion has also been linked from Reddit:

[http://www.reddit.com/r/haskell/comments/1gknfs/ask_hn_any_d...](http://www.reddit.com/r/haskell/comments/1gknfs/ask_hn_any_downsides_of_programming_in_haskell/)

------
ciderpunx
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
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.

------
carterschonwald
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
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
Monad transformer hell.

~~~
raphinou
Can you share a bit more? I'm not familiar with Monad transformers.

~~~
LukeHoersten
Monad transformers are just monads wrapping other monads. I actually like it
and think it's a really clean way to organize your state, IO, etc. For
example, you could have a Reader wrapping a Writer wrapping a State wrapping
IO. The reader is your configs, the writer is for error logging, the state is
for some application map, and the IO is for doing networking or something.
That's an extreme case but it's nice to lay it out in that way.

~~~
mynameisme
lurker14, you're shadow banned. He/she said:

That's a special case, because RWS already exists (Reader, Writer, and State
all commute), and wraps IO easily.

Light overview of the issue: [http://ro-
che.info/articles/2012-01-02-composing-monads.html](http://ro-
che.info/articles/2012-01-02-composing-monads.html)

It's the other cases that get head-desk-banging. This paper is great, but
shows what a high mental tax you pay to get highly-principled programs:

[http://www.grabmueller.de/martin/www/pub/Transformers.en.htm...](http://www.grabmueller.de/martin/www/pub/Transformers.en.htm..).

At the end of the day, most people on most projects seem to prefer sacrificing
some formal specification (and some actual correctness) for getting code
running for the common case.

Related reddit conversation:

[http://reddit.com/r/haskell/comments/rd2t5/i_love_rwst_r_w_s...](http://reddit.com/r/haskell/comments/rd2t5/i_love_rwst_r_w_s..).

------
papsosouid
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.

~~~
mightybyte
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.

~~~
dllthomas
I'd be interested in hearing, too, so please make it public if you're
comfortable with that (and link it here, if the conversation isn't held here).

