
Why Haskell Is Worth Learning - ColinWright
http://spin.atomicobject.com/2013/03/05/why-haskell/
======
cletus
I have to admit that I'm really on the fence about Haskell. My major gripe
with this point I think is point (3).

Haskell has (IMHO) gone down a similar road to Scala. Scala has literally tied
itself into knots to make statically typesafe collections (amongst other
things). I see parallels with Haskell (maintaining functionality purity but
dealing with the "outside world" through monads).

I'm not saying this is wrong. What I am saying is that the gap between making
something 99% consistent and 100% consistent is often huge in terms of
complexity. This is why I think the so-called mixed paradigm languages
(Python, Ruby, even C#) have done so well since you can use these programming
models while still writing easy-to-understand imperative code.

This is also why I'm so bullish on the future of Go. Someone wrote a book
called Learning Go that tells you most of what you need to know and you can
knock that out in an afternoon. Go has a good model for parallel programming
and a simple syntax. It has made the choice of simplicity over completeness
(eg no "generics").

The net effect is that Haskell will never be mainstream (IMHO) because it's
too complex whereas Go probably will be because it's incredibly simple.

We've had complex functional languages (eg Lisp) for decades. Yet they haven't
gone mainstream. You have to ask yourself why. Some pride themselves in using
something so esoteric. Others attribute the lack of popularity to poor
marketing or bad timing. The answer is (again, IMHO) is that simplicity
matters.

Now it should be noted that we're talking about _perceived_ simplicity. You
can write multithreaded code in Java, C or C++ but getting it right is
incredibly hard yet it can appear simple. The goal of any language I think
should be to narrow or eliminate the gap between _perceived_ simplicity and
_actual_ simplicity. IMHO Go does a remarkably good job of this.

FWIW Python and Go also play nice with C.

It's true functional programming does change the way you think but I think
writing idiomatic Python or Ruby will get you much the same benefit at much
lower cost.

~~~
tikhonj
Haskell is also very simple--not from an implementation standpoint but from a
semantics standpoint. Having polymorphism with no sub-typing (and no casting)
is conceptually simple and easy to work with. Parametric polymorphism (like
Java's generics but simpler and less horrible) is actually an extremely simple
concept. The difficulty comes from a) implementing it in a stupid way after
the fact ( _cough_ Java) or b) having sub-typing. Neither is necessary!

In this day and age, semantics are far more important than implementation.

You can fit Haskell's evaluation rules and its typing rules on one page.

Haskell's syntax is also very simple and consistent. It has fewer constructs
than most imperative languages--fewer constructs than anything short of Lisp.
It just also happens to be much more flexible than other languages.

Moreover, much of Haskell's syntax is _very_ transparent syntax sugar. You can
easily desguar it in your head. It makes code nicer to read but does not add
any real complexity because it trivially maps to a bunch of simple function
calls.

Most of Haskell is a very transparent layer over a typed lambda calculus.
Lambda calculus is basically one of the simplest possible constructs. Ignoring
the type system for a moment, it has literally _three_ concepts: functions,
variables and application. We then throw in some very straight-forward
extensions like numbers, add a bit of syntax sugar and a type system.

The type system is also surprisingly simple. It has to be, for the inference
to work! It's also very consistent in the way that is almost unique to
mathematics. Consistency is pretty important.

This is where I shall bring up the "Simple Made Easy"[1] talk. It comes up a
lot in these discussions, for a reason: most people mix the two up. I don't
agree with _all_ the points in the talk, but the core message is completely
correct and very valuable.

[1]: <http://www.infoq.com/presentations/Simple-Made-Easy>

Simplicity _is_ valuable. And Haskell, for all its being hard to learn, _is_
simple.

IO is a great example here. Monads are difficult to learn, granted. But they
are not _complex_. Rather, they are _abstract_. In fact, monads are extremely
simple; the actual difficulty is twofold: it's not immediately obvious why
they matter and they're too abstract to permit any analogies. Ultimately, a
monad in Haskell is just any type with three simple functions that behave
consistently--it's just an interface.

Go is not particularly simple; rather, it's easy. It's familiar. The syntax is
more arbitrary, but it is C-like. The built-in constructs like loops are more
complex and arbitrary (Haskell, after all, has no built-in iteration at all),
but hey, it's C-like. The exposed features? Again, fairly arbitrary.

That's how I would sum up Go's design: arbitrary. And mostly C-like. Where C
itself is pretty arbitrary. Especially from a semantics standpoint.

Essentially, Go has whatever the designers felt like adding. Just look at all
the different ways you can write a for-loop! Or the fact that you have a loop
at all. Haskell, on the other hand, has a deep and elegant underlying theory
which ensures that different parts of the language are all consistent.

Haskell is much less arbitrary. Most of the features naturally go together.
Many are just generalizations or facets of the same concept. Even the
complicated, advanced features like "type families" or "GASDTs" are just
fairly natural extensions of Haskell's basic concepts. It's very much akin to
mathematical ideas, which have an elegance and consistency eluding most other
languages.

Here's a particular example of how the features fit together: algebraic data
types. Haskell essentially has two fundamental ways to create data types: you
can combine fields into a record (like a struct) or you can have a choice (a
tagged or disjoint union). The really neat bit? These aren't arbitrary--
they're actually deeply related. In fact, they're duals of each other. Having
both makes the most sense.

It also gives you a much better way to signal errors. In Go, for whatever
reason, errors are essentially built into the language as an implicit tuple.
However, in practice, you _either_ have a result or an error. If you have an
error, the result is meaningless; if you have a result, you shouldn't have any
error! So it makes _much_ more sense to represent errors as a variant, a
choice--a sum type. This lets Haskell avoid baking in error handling into the
language, making it simpler.

Haskell is as mixed-paradigm as the languages you listed. Those languages are
imperative with some _weak_ support for functional programming. Haskell is
functional with some _weak_ support for imperative programming. It's the same
idea, inverted. Except Haskell can also support things like non-deterministic
and logic programming. It's just that, for some reason, when people say
"mixed-paradigm" what they really mean is "imperative with some functional
support" and never "functional with some imperative support".

Sure, Haskell's syntax for mutable structures is awkward. But have you seen
C#'s or Python's or even Go's syntax for functional programming? Compared to
Haskell, it's just as awkward! And Haskell's "syntax" for mutable constructs
is just a library; it can be improved. It just turns out that imperative
features aren't useful enough for experienced Haskellers to warrant the
improved syntax. (Also GHC sucks at optimizing sufficiently complex imperative
code, I gather.)

There's a nice example of what you can do on Lennart Augustss's blog[2]. He
essentially embedded a very C-like language into Haskell without using macros.
So it's certainly possible, just not worth it.

[2]: [http://augustss.blogspot.com/2007/08/programming-in-c-
ummm-h...](http://augustss.blogspot.com/2007/08/programming-in-c-ummm-haskell-
heres.html)

So yes, perhaps Haskell will never be popular. But that's a social issue. It
is not an issue of the language's qualities.

And it shouldn't stop you from using Haskell. At your startupt. Hint, hint.

~~~
pekk
It is an issue of the language's qualities if it does not really make it
easier to reason about code.

I find reason to question the simplicity of something which is widely
acknowledged to take a lot of time to learn, to be mind-bending, and which
seems to be impossible to explain simply - without deep theoretical
background, academic citations or oversimplifications acknowledged as
misleading.

I think it would be mature for the Haskell community to occasionally
acknowledge a trade-off of the language. Haskell's flaws are not all "social
issues." The virtues of survivors like C and LISP are not all "social issues".

~~~
tikhonj
Simple does not imply easy. As an extreme example, a unicycle is simpler than
a bicycle--fewer components, simpler structure, no gearing--but also more
difficult to learn.

Really, I'll just have to point you to the "Simple Made Easy" talk again. The
core point being that there's a difference between something being "simple"
and something being "easy", and we should generally strive for the former
rather than the latter.

Having a deep theoretical foundation is also not a sign of complexity.
Instead, like most of math, it's usually a sign of simplicity. After all, math
always strives for elegance and simplicity.

What it means is that a lot of smart people have spent a lot of time thinking
things through using a strict framework for reasoning that ensures everything
is consistent. The theoretical framework lets us _simplify_ by recasting
different concepts using the same fundamental ideas. If we can capture things
like state, errors and non-determinism using a single concept, we've made
things _simpler_ because now we have a common ground and relationship between
seemingly disjoint ideas. This is exactly what Haskell (and the theory behind
it) does.

This theoretical foundation, coupled with the relative simplicity and
consistency of the language, actually make code much _easier_ to reason about
in Haskell than in other languages, except for some performance issues.
Basically, as long as your main concern is in semantics--and, for 90% of your
code, it is--Haskell makes life easier than any other language I know. You can
manipulate the code purely algebraically, without worrying about what it does,
and be content that the meaning remains the same.

Having well designed libraries with actual algebraic laws governing their
behavior, a powerful type system and very transparent syntactic sugar is what
makes the code particularly easy to reason about. A simple, elegant semantics
also really helps. You can really see the influences of a good denotational
semantics when using the language.

Now, reasoning about _performance_ is sometimes an issue. It's certainly
reasonably hard without additional tooling. Happily, there are some nice tools
like criterion[1] to make life easier for you.

[1]: [http://www.serpentine.com/blog/2009/09/29/criterion-a-new-
be...](http://www.serpentine.com/blog/2009/09/29/criterion-a-new-benchmarking-
library-for-haskell/)

Also, the Haskell community does acknowledge trade-offs. They're just not the
same trade-offs that people not knowing Haskell lambast. Which should not be a
surprise--you can't expect somebody who hasn't really learned Haskell or its
underlying ideas to have a thorough idea of what its real problems (or even
its real advantages) are.

~~~
joe_the_user
Watching the video now...

It seems beautiful, enlightening and wrong.

It might be described as a powerful statement of software idealism.
Essentially, start simple and stay there, the problems, the mess, the
mythical-man-months, etc all come because the developers refused the effort
needed for simple and impatiently descended into the swamp of complexity.

I too, love starting simple and usually intend to stay there.

But the problem I would suggest, is the complexity will build up and simplity-
as-the-simple-methods you've learned, simplity-as-such, can't fight this
build-up. _If being simple COULD put an end to complex situations, you
wouldn't have to START simple, you could use simplicity to "drain the swamp of
the complex"._ But every methodology more or less says that you have to be on
the top of its mountain and to stay there (except original OO and we know how
well that worked).

My contention is that this "mountain dwelling" is only possible at times, in
some domains, in some organizations, etc. Humans can, at times, carve
simplicity out of the swamp of complexity. But it isn't easy and it isn't a
product of any fixed set of simple tools we human have come up with so-far.

Mr. Hickey's viewpoint might be useful for selling simplicity and I would be
willing to use it if I thought simplicity would be a good buy for my
organization. But the reality is tradeoffs never good away. Sometimes people
overestimate the value of short term payoff but sometimes people overestimate
the value of long term payoffs. The one thing that I think I want to keep here
is the clear, simple distinction between "ease" and "simplicity". It's useful
even if it might not be entirely, true.

------
freshhawk
I love haskell but I wish there was less blogging about why everyone else
should use it and more building things that will make people want to use it.

The community is extraordinarily friendly to beginners, as long as you only
count how they interact with beginners. If you count having resources that
allow beginners to figure something out without having to ask then they are
extraordinarily unfriendly.

If I find a potentially interesting library on hackage I'm no longer surprised
to find it has no documentation at all, certainly no usage documentation or
explanation of what it actually does or what it should be used for. Just code
and autogenerated API docs. I'm surprised if there is anything that would
allow me to actually use it. I'm not often surprised this way.

That and the wild west, "not invented here", multiple incompatible
implementations of new ideas used in different important libraries (iteratees
at the moment).

Not trying to throw blame around of course, but people probably don't need
your "I have a new metaphor for monads" blog post or an argument for why it's
worth learning. People need more posts like the 24 Days of
Hackage(<http://ocharles.org.uk/blog/>) series and the Real World Haskell book
and they need some brave person to try and convince those amazing library
developers to standardize on an imperfect solution a little sooner and for a
little longer (only in public of course).

~~~
tel
I think generally the advice to beginners is to ignore most of Hackage and
focus on the Haskell platform—which is frankly kind of terrible advice. It's
intended to avoid things like the enumerator/iteratee/conduit/pipes madness
and focus on a stable library interface, but almost all of the fun is being
developed on the bleeding edge of Hackage.

I'd agree completely that this is a deficiency with the Haskell community, but
I also don't see it stopping until there's a larger critical mass of new
users—a chicken and egg problem, certainly.

~~~
freshhawk
I don't think it's a chicken and egg problem quite. It's true that the types
of people that do these kinds of things arrive when you have critical mass,
but that's just statistics.

I think you can recruit people to do this kind of thing, or at least encourage
people to do so, but it would require community management and such which
doesn't really exist in the haskell community. If I felt cruel I would
nominate dons to do it, since it's so easy to want to give more work to the
guy who's already doing a ridiculous amount of good work.

------
tel
Haskell is just playing a different game. Clojure/Scala/F# might also be
playing that game or something somewhat like it, but until you start to
realize just how relaxing pure, statically checked code is you're coding in a
tar pit.

Even the IO system is better because you think of it as nothing more than a
way to manipulate and combine a kind of pure data corresponding to sequences
of "real world" actions.

------
Millennium
I was told to learn me a Haskell for great good. Is that not enough for people
anymore?

~~~
bobajett
I started with LYAH loved the first 6 chapters. Got bogged down on the 7th
because it was more abstract. Now Im reading both LYAH and Real World Haskell
and reading both makes a great combination. If I get bogged down in one the
other keeps my momentum going.

------
minimax
I was thinking about this the other day and I think it generalizes beyond any
specific language. I'm pretty sure every time I have learned a new programming
language I came away a better programmer. Different programming languages (and
their standard libraries) suggest that you approach problems in different
ways, and that has real cognitive benefits.

I was actually trying to think if there was ever a case where I had spent time
learning a language (or library) that didn't pay some sort of dividend in
terms of increasing my skill as a programmer.

~~~
tmoertel
The point about learning Haskell in particular is that it's a _way different_
different language. It's a single language that gives you exposure to a lot of
new ideas: purity, laziness, modern type systems, functors, monads, monoids,
etc.

~~~
solistice
The massive difference though gives people like me, who've never done anything
like Haskell before and do not properly comprehend it some real trouble
though. It's similar to assembler. At first, you don't understand how the code
works, how the logic is implemented, and everything just seems strange. Then
you start looking at it as seperate commands to the processor and suddenly you
understand. Sudenlly MOV r1,0x90 start: MOV A,#0x04 INC A DJNZ r1,start makes
sense to you.

Sorry, I started fantasizing about Assembly again, my actual question was: "If
you could find a metaphor that describes how Haskell works with Data, what'd
be that metaphor?"

------
kreek
I investigated Haskell for a while and as long as I didn't try to add any libs
it was fun. However once I started using cabal to try and manage dependencies
all hell broke loose. Obviously it takes a while to get it right (looking at
you SBT and Ruby gems) but Haskell has been around forever.

~~~
papsosouid
I'm writing 3 different web apps, plus some command line tools in haskell. I
have been working on these projects for a year now, and I've never seen any
cabal problems that aren't typical problems that occur with any package
manager (trying to install conflicting modules).

    
    
        $ ghc-pkg list | wc -l
             182

~~~
tel
I felt that way up until last week! I somehow felt I was special, that cabal-
hellfires had burnt a ring around me. Then next thing I knew I had a 4 page
cabal conflict problem and had to just toast .ghc and .cabal and start over.

It's a real problem.

~~~
gtani
you could look into hsenv and cabal-dev.

<https://github.com/cakesolutions/the-pragmatic-haskeller>

[http://bob.ippoli.to/archives/2013/01/11/getting-started-
wit...](http://bob.ippoli.to/archives/2013/01/11/getting-started-with-
haskell/)

Also, problems in the haskell ecosystem don't stay problems for long, this one
is the longer end of the tail

[http://alpmestan.com/posts/2012-11-02-cabal-hackage-what-
you...](http://alpmestan.com/posts/2012-11-02-cabal-hackage-what-you-can-do-
about-it.html)

~~~
tel
I do use .hsenv a lot, but for simple playing around with libraries (where I'm
also most likely to hit major version overlaps) I liked to keep installing
packages into the user level database.

------
gfodor
I'm at the point where I have zero interest in learning new languages to
"expand my mind" unless they have very obvious application to problems I am
facing right now. For example, Matlab sucks, and scientific computing sucks in
most other languages, so learning Julia is probably worth my time. What is
Haskell's killer domain? Meta-programming C code seems more than a little
esoteric for it to be worth the massive investment of time and opportunity
cost of curling up with a Haskell book and a REPL in my free time. I spent a
lot of time learning Clojure, which is an amazing language, but here I am
years later and I still reach into my toolbox of imperative languages (C,
Ruby, Matlab, Java) to solve any "real" problems quickly, efficiently, and in
the most straightforward (and understandable by mere mortals) way.

If I want to expand my mind (towards the end of building software) I will fire
up Coursera and study math or algorithms, things which are, imho, more widely
applicable, timeless, and have a "bigger bang for the buck" for self-study
than learning another programming language.

~~~
oscilloscope
Algebras? I learned some basic Haskell: the type system and algebraic data
types.

When I went to study group theory, I found it came easily. Now I'm working my
way towards lie algebra. The cool thing about Haskell is for any particular
algebra, there's often a good tutorial or literate Haskell implementation.
Picking the right algebra for the problem domain can save you a lot of
computation, but once you understand how it works you're always free to drop
back to an imperative language to do the computation. Haskell makes it easy to
play around and discover deep relationships, but it does require being an a
mind-expanding mood to get to a comfortable place.

------
dschiptsov
_That complex function will turn out to be not all that complex at all; it can
be written as just three simple functions composed together!_ \-- Why this
requires to learn Haskell, instead of ML or Scheme or Erlang?

~~~
prg318
The skill of breaking down large functions into smaller simple functions is a
common skill of programming and should be practiced in all languages (C, Java,
Python, etc). I'm not really sure from the article what I am supposed to gain
by learning Haskell.

I'm not debating the opinion that Haskell is great language to learn, but the
benefits of learning the language were not clear to me after reading the
article. Does anyone care to elaborate?

~~~
jerf
"The skill of breaking down large functions into smaller simple functions is a
common skill of programming and should be practiced in all languages (C, Java,
Python, etc)"

Haskell will show you that when you _thought_ you broke your code down into
small functions in those languages, you were wrong in ways you currently can't
even see and they're still shot through with duplication and mixing of
concerns.

This is really the core of the "it changes how you program"; the environments
you mention are so full of conflation of IO and mutation and state that you
don't even see it, because it's just the way it is. Haskell will ungently pry
those apart for you, if you stick around long enough to actually become
proficient. You can take this back into other programming languages where this
separation is not enforced, but I'm not convinced you can _learn_ it where it
is not enforced. The feedback cycle is so direct in Haskell ("Type Error:
...") and so diffuse in other languages (two months later "Aw crap, I should
have isolated IO from non-IO better...").

(Oh you think that last parenthetical is a joke? Ha! I wish.)

~~~
xaa
Learning Haskell taught me that mutation and state are _good_ things, present
both in the fundamental nature of computers and the real world. Haskell's
attempts to eliminate state entirely results in a profound increase in
complexity.

For me, learning Haskell was like visiting a third-world country:
enlightening, very different, but ultimately I leave feeling very grateful
that I'm not a permanent resident. All in all, I would recommend the
experience.

~~~
papsosouid
It doesn't sound like you actually did learn haskell. Haskell does not in any
way make any attempt to eliminate state, and the idea that it does is absurd.
Why would the language ship with a module called "State" if it were trying to
eliminate state?

~~~
rafcavallaro
Substitute "treat like a pariah" for "eliminate" and you're good to go!

------
dkhenry
I am no Haskell expert, so I might be wrong on this, but is that code right ?
I would imagine the fourth line should read

    
    
        isIfOfInterest (CIf cond _ _ _) = not (null (listify isFooIdent cond))
    

not

    
    
        isIfOfInterest (CIf cond _ _ _) = not (null (listify fooIdent cond))

~~~
pestaa
You are correct. The nice thing is that this mistake would have been caught
compile-time.

~~~
lolcraft
You mean, "identifier not found"... ?

~~~
pestaa
Exactly. Ever tried running PHP, Ruby or Python code with an undefined
variable somewhere? It works flawlessly... for a minute... an hour... or a
month... and then it suddenly hits you out of the blue.

------
Surio
Relevant points on Haskell, from another discussion, and sort of echoes my own
thoughts:

<http://news.ycombinator.com/item?id=5314701>

<http://news.ycombinator.com/item?id=5314507>

~~~
octo_t
At university the very first language we are taught is Haskell. Lots of people
had never programmed before, in _anything_ and everyone managed fine. Nothing
scary at all, no need for an understanding of category theory or anything.

Monads are (fairly) simple things that just have a really bad reputation,
partly the fault of the haskell docs which make them seem complex.

Firstly:

Functors are things we can map over in a logical way; thats it. Monads are
just a fancy way of saying "side-effects might happen here" (obviously not in
all cases, but its fair enough for most uses - things like the Maybe Monad are
not side effects)

~~~
redman25
I'm curious what school you went to, there can't be a lot of universities that
teach Haskell?

~~~
wting
University of Texas at Austin teaches Haskell to 2nd year students in a
required course: CS 337 - Theory in Programming Practice.

Programming Languages is also taught in Haskell, but it's an optional course
and languages varies by professor.

------
MrMan
I will learn Haskell if you people will stop spamming me about it.

~~~
tikhonj
I dunno, even on here it gets less press than Python, Ruby or even Go. It's
just since most people already know imperative programming well, the
Python/Ruby/Go articles that get upvoted tend to be a bit more advanced.

Will you stop using Python? Or would you not learn Python?

------
axilmar
Does FP really help reasoning about programs in a better way? I have a hard
time believing that, since what ever logical errors I do in programs can
easily manifest themselves in FP programs as well.

Having tried a little Haskell myself, the same bugs that I have in imperative
code also appear in functional code, albeit with a different form.

