
Ask HN:  Why Haskell? - csense
I was hating on Haskell the other day.  A lot of HN&#x27;ers apparently love it, because my comment was downvoted.<p>One of the replies said:<p>&quot;I&#x27;ve seen experienced programmers failing at learning Haskell...the initial learning curve is very steep, and they don&#x27;t see the value on climbing that wall...with Haskell, all those seemingly complex concepts come with a big reward.&quot; [1] [2]<p>My question is:  I currently don&#x27;t see the value proposition of learning Haskell.  What is this great enlightenment I&#x27;m supposed to receive from studying Haskell?  Can someone give me the TLDR version?<p>PS:  If you say &quot;functional programming&quot;, please elaborate.  I know all about function pointers in C, and I&#x27;ve read the docs of Python&#x27;s functools module [3].<p>[1] https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=7478274<p>[2] I don&#x27;t want this thread to degenerate into a favorite editor flamewar the way the other one did, so I&#x27;m leaving out the commenter&#x27;s clearly preposterous claim that learning vim is worth your time.<p>[3] http:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;functools.html
======
cjbprime
Perhaps three things:

* Haskell is (very) strongly and statically typed and Python isn't. Haskell's type system can prove the correctness of many functions at compile time. In contrast, Python usually waits until runtime to throw exceptions, even for something obvious like a syntax error.

* Because the types are known, there's an incredibly powerful testing framework called QuickCheck that is capable of e.g. generating tens of thousands of valid inputs and seeing if it can automatically disprove your assertions about your code. Python's typing is insufficient for this.

* Qualitatively, writing Python feels like writing instructions for computing something, and writing Haskell feels like simply describing what something _is_ , and the system works out how to compute it for you. It often feels compelling and magical.

Lastly, some tone stuff: Function pointers have nothing to do with functional
programming. And why hate on a language you haven't studied? And why does
there _have_ to be a TLDR version of a mind-expanding experience like learning
a new programming style? Why form a strong opinion about something you don't
know in the first place, and why feel entitled to challenge someone to explain
it all to you? It's pretty frustrating.

~~~
Ingon
_> Because the types are known, there's an incredibly powerful testing
framework called QuickCheck that is capable of e.g. generating tens of
thousands of valid inputs and seeing if it can automatically disprove your
assertions about your code. Python's typing is insufficient for this._

I think immutability also helps on this front.

~~~
SamReidHughes
Just being statically typed helps, there's nothing particularly special about
Haskell that makes QuickCheck possible.

~~~
coolsunglasses
Have you read the source to Haskell's QuickCheck?

It can automatically derive automatic randomized generation of your data-types
_FOR_ you. No other generative testing library (such as for Clojure or Erlang)
can do this.

Further, the random data generation can be customized using the functional
combinator API.

Haskell QuickCheck's source code is a compelling example of what can be done
with static types and typeclasses in Haskell.

~~~
SamReidHughes
> It can automatically derive automatic randomized generation of your data-
> types FOR you.

There's nothing about Haskell (or some extension to Haskell, I presume) that
makes this possible that wouldn't make this possible in other languages like
C#, Java, or, with a bit more verbosity, C++. If I'm wrong, please say what it
is, I'd love to know.

~~~
coolsunglasses
You're wrong and you should look into how typeclasses, derivation, SYB, and
GHC generics work.

That they _aren 't_ doing it is reason enough. Clojure and Erlang's QuickCheck
libraries would derive Arbitrary if they could. :)

~~~
SamReidHughes
I already know how they work. Still waiting for an explanation of what they
can do that you couldn't do in Java or C# or (with some verbosity) C++.

Edit: For example, to answer this question, you could define a type and
explain how Haskell lets you automatically generate arbitrary instances of
that type, where Java or C#, being as limited as you claim them to be, would
be incapable of doing so. Edit: Also, Clojure and Erlang are irrelevant. My
comment you originally replied to said that static typing was what makes
QuickCheck possible.

~~~
revcbh
Let's use circles and rectangels to motivate some analysis. In Haskell you
might define:

    
    
      data Point = Point { x :: Float, y :: Float }
        deriving(Generic)
      data Shape =
        Circle { center :: Point, radius :: Float }
        | Rectangle { topLeft :: Point, bottomRight :: Point }
          deriving(Generic)
    

In C# you could similarly define

    
    
      class Point {
        public float _x, _y;
        public Point(float x, float y) {
          _x = x;
          _y = y;
        }
      }
    
      interface Shape {}
      class Circle {
        public Point _center;
        public float _radius;
        public Circle(Point center, float radius) {
          _center = center
          _radius = radius
        }
      }
      // etc, for Rectangle ...
    

Let's start from the C# end of things. Let's say we want to do some tests on
random Shapes and that we want to get an instance of a random shape by calling
Generate.random<Shape>(). There are a couple of different ways to do this. We
could explicitly define a RandomShapeFactory and a RandomPointFactory and then
wire those up into the Generate class. Maybe we could use reflection to
dynamically generate instances of Points and Shapes from their definitions at
runtime. It would probably end up looking like some combination of the two.

Haskell doesn't let you magically generate random instances of Shape. The cool
thing it gives is the "deriving(Generic)" part. Effectively, this causes the
compiler to generate a description of Point and the Shape-Circle-Rectangle set
of types. In many ways, it's like C#'s reflection. The QuickCheck library uses
this reflection-like definition to generate random instances.

The core functionality isn't very different, but Haskell's approach has a
number of advantages. Most importantly, it's type-checked at compile-time. In
the C# version, I could call Generate.random<Cat> and the code would blow up
at run-time, whereas we would just get a compiler error in Haskell. The other
major advantage in this case is the reduction of boiler-plate. There's no need
to register factory instances inside of some singleton object at startup, the
type system can infer which Generic components are needed where.

C# and Haskell are both turning complete, so you can do anything in either
language. Haskell makes certain types of programming more enjoyable by
reducing boiler-plate and preventing annoying runtime errors.

EDIT - code formatting

~~~
SamReidHughes
> There's no need to register factory instances inside of some singleton
> object at startup, the type system can infer which Generic components are
> needed where.

You would only need to do that if you wanted to define custom behavior,
instead of automatically derived behavior, and registering a few delegates is
the same amount of work as manually implementing an instance of Arbitrary and
CoArbitrary.

~~~
revcbh
Yep. The only really-real difference is compile time checking.

------
jberryman
When haskell programmers say "functional" they mean "functions, like in math":
yes, mathematics has higher-order functions (derivative, etc) but the main
thing is a mathematical function doesn't fire missiles or mutate variables
(what we call "side-effects"). Writing code that's like math is "declarative";
you describe _what things are_ not _what to do_.

Others have given lots of good views on the various upsides to using haskell,
especially the ways in which the type system can catch bugs for you. But my
favorite thing about the type system is it lets you create good abstractions.
For example it's possible (and often quite easy) to create a library which
_cannot be used incorrectly_. And because you finally have abstractions which
are good (not brittle or leaky) you can build on them to create larger
abstractions (by "abstraction" here, think: conceptual unit that is easy to
reason about). And that's also one of the challenges with learning haskell:
there's more to learn because we can create new abstractions that are worth
learning.

I like talking about haskell, but certainly won't presume to tell you you
should learn it. But if you want to learn and are put off by what you've seen
of it on HN for whatever reason, I can tell you that the community is
incredibly generous and full of very kind and smart folks (though some
humility and an open mind, as always, will get you far). The community is why
I actually have something of a career in software today.

------
coolsunglasses
Edit:

Before Haskell, I used Common Lisp, Python, and Clojure. I was impatient,
generally more interested in hacking than math, and was happy using untyped
programming languages.

Haskell changes the equation, it (alone, for now) provides even better
leverage and expressiveness than untyped languages like Clojure, Python, or
Ruby. Further, it does so in a way that is more powerful and reliable because
you have the leverage of the type system behind you.

Learning to think about code in terms of types is a transformative experience.

Types is where the future is headed.

I've been getting people started with Haskell for the last ~3-4 months. It's
not that hard to learn at all if you use proper learning material and do the
exercises.

Don't waste any time, just learn Haskell and find out for yourself.

My guide for learning Haskell:

[https://gist.github.com/bitemyapp/8739525](https://gist.github.com/bitemyapp/8739525)

~~~
SamReidHughes
Have you ever used any other statically typed languages? How much of Haskell's
benefit do you think it provides that simply having static typing doesn't
provide?

~~~
quchen
\- Haskell types often guide development: the error message ("type mismatch:
expected blabla") gives you strong hints about what sort of error you've made.
The magnitude of this one is hard to convey by merely writing/reading about it
though.

\- Easy wrapping to create new types: Ever switched the arguments of `mv` in
your terminal (strings)? Read the User ID as an account balance (ints)? You
can distinguish these statically, and it's easy to do so. (You can of course
write a wrapper class in C++ around Int as well a la "class OtherInt { int
value; int get(); set(int i) }", but how often do you do that?

\- No IO in a type? It cannot do IO. Has "Monad" in the type? It can do
Monadic stuff, but no operations specific to any Monad instance (such as
Maybe, IO, ...).

\- Types are forced documentation. Don't get me wrong, no documentation is as
awful in Haskell as it is anywhere else. However, even without any ordinary
comment, a type can give away a lot of what a function does; maybe even more
importantly, it tells you what it cannot do. If you see something of type `(a
-> b) -> (a -> a)`, you know that the first argument cannot possibly be used -
it has to be a dummy parameter.

~~~
mushly
How do you do documentation in Haskell? For Python and Clojure, there's
docstrings. For Java there's Javadoc. For Haskell, there doesn't seem to be
any well-established documentation practices.

This is of course not counting the occasional comment explaining why/how
you're doing something convoluted.

~~~
quchen
> For Haskell, there doesn't seem to be any well-established documentation
> practices.

Oh yes but there is! It's called Haddock. It's widely (and probably
exclusively) used. The entirety of the documetation you can find on Hackage
[1] (example: [2]) is generated using it. The user guide can be found here
[3].

[1]: [http://hackage.haskell.org/](http://hackage.haskell.org/) [2]:
[http://hackage.haskell.org/package/pipes-4.1.0/docs/Pipes-
Pr...](http://hackage.haskell.org/package/pipes-4.1.0/docs/Pipes-Prelude.html)
[3]:
[http://www.haskell.org/haddock/doc/html/](http://www.haskell.org/haddock/doc/html/)

------
maxcan
One aspect that doesn't get mentioned much is recruiting from both sides.

As an engineer, if you land a job coding haskell you're pretty much guaranteed
to be an environment thats extremely engineering-centric, has minimal
technical debt, and is staffed by lots of smart people. usedox.com, alpha
heavy, jane street (ocaml but close enough), silk, tsuru, fobo are all
exemplary examples of this. anyone of them is an amazing environment and
you'll learn a ton. (the first one is my own company, so consider that one
with a grain of salt)

As an employer of engineers, if you put out a call for haskellers, you'll get
a far smaller applicant pool than say ruby, python, java, or c#. But the
signal to noise ratio is incomparably higher. Very few mediocre engineers will
claim haskell as a skill.

~~~
dustingetz
Hi. At your company and other Haskell teams that say they hire elite
engineers, is an engineer's compensation higher than comparable non-FP shops?

Please forgive the bluntness; as a guy who is about halfway down "the road to
Haskell", it seems like none of the shops that say they value FP are willing
to pay more for it. For me, it's been easier to extract money from a javashop
that's starved for talent and just figure out a way to install FP there. DK
effect might also be clouding my self valuation.

~~~
maxcan
DK effect?

I can only speak to my current company (dox) and Jane Street, where I worked a
long time ago.

At JSC, comp was above market and everyone was quite happy but they've
quadrupled in size since my time so YMMV.

As Dox, we are currently bootstrapping off of a small round and everyone is
working well below market in terms of cash but with commensurately higher
equity. we will be raising a round later this spring and intend to roughly
match or exceed comparable shops when that round closes. we've been completely
transparent about that to the entire team as they've all taken pay cuts to
work with us a this early stage, something we respect and are extremely
appreciative of.

If immediate salary is a principle concern, probably best to look at JSC, Stan
Chart, or Barcap rather than a place like us or one of the other startups.

~~~
dllthomas
_" DK effect?"_

[http://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect](http://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect)

------
dwc
A while back I was learning Haskell. I had a problem I wanted to poke at a
bit, so I thought I'd give it a try. So I made various types in Haskell's
nifty type system, which is NOT hard or tricky. I made some functions to work
with the types. Easy. I worked all this stuff up and tried to compile, and
being that I wrote a fair amount of code of course there were a couple of
typos, etc. But then there was another part that wouldn't compile because I'd
made an error, and the type system called me out on it. It's like getting the
benefit of _unit analysis_ (or _dimensional analysis_ ) from the compiler.

That's one thing to like. A lot. There are other things.
Polymorphism/overloading through type classes is so easy and clean it's hard
not to love. The list goes on and on.

For my part, I got hung up a bit on using monads. This was a few years ago, so
maybe there are better articles/explanations now, but at the time there were a
zillion monad tutorials, all of them written by people who almost but not
quite "got it". I need to try Haskell again.

~~~
quchen
The _Monad tutorial fallacy_ is an in-joke in the Haskell community nowadays,
born out of what you observed: when people feel like they understand monads,
they are so happy about it that they write a bad tutorial about it.

My advice: Monad is a typeclass, and typeclasses unify things that act alike.
Learn Monad instances (List, Maybe, State, ...) separately without worrying
about how they are "monadic". After some time you will develop an intuition
for what do, <-, return, >>= etc. have in common. And that's what Monad is.

------
dllthomas
_" [2] I don't want this thread to degenerate into a favorite editor flamewar
the way the other one did, so I'm leaving out the commenter's clearly
preposterous claim that learning vim is worth your time."_

Asserting that a "claim that learning vim is worth your time" is "clearly
preposterous" is not exactly the straight and true path through the valley of
flamewars.

------
simplify
Short version: Most, if not all programming bugs are due to your code
receiving something it did not expect. Haskell's type system helps eliminate
this problem by forcing your code to declare exactly what it expects, and to
handle all cases of said expectations.

In other words, it's doesn't let you skip out by not thinking about the
entirety of your code. It's the same line of benefits that TDD gives you, but
TDD is, IMO, a stepping stone towards the pure, functional programming that
Haskell provides.

Note that I am by no means a Haskell programmer. To me, Haskell is the "last
level" in learning development. I hope to one day reach such a level.

~~~
SamReidHughes
> Short version: Most, if not all programming bugs are due to your code
> receiving something it did not expect. Haskell's type system helps eliminate
> this problem by forcing your code to declare exactly what it expects, and to
> handle all cases of said expectations.

No it doesn't (force). It's about as good as C++ on this front, with better
error messages. What it does do is make it a lot easier to program in a style
that handles all cases, but without forcing you to do so. You can pattern
match on something instead of making a visitor. But you can still call head or
tail.

~~~
coolsunglasses
Your comment misrepresents the reality for Haskell programmers.

~~~
SamReidHughes
If you wanted a useful reply you could explain how. The grandparent has things
backwards -- it's possible for functions to force restrictions on their
_callers_ (by forcing them to pass a pure function as a parameter). The caller
can't _force_ the callee to consider all cases of its input.

------
dllthomas
Haskell's biggest win is the power of its type system, including its ways of
getting types places other languages simply can't.

In C and Python, "a statement" is a different kind of thing than "an
expression". Statements don't "have types" \- the expression that makes it up
may, but the value winds up discarded and the type doesn't matter (except
maybe to produce a "unhandled value" warning, if you've set things up for
that).

In Haskell, statements are just another kind of expression, and the types of
those expressions determine how they get chained together. This means I can
leverage the type system to help me avoid new kinds of errors - want to be
sure you don't try to do I/O in an STM transaction? Or access that variable
from the wrong thread? Or... In Haskell, that's straightforward. In C, that's
not something you can express and you have to check it all by hand.

------
clin_
Here's a handful of things I really appreciate about Haskell, although some of
this apply to other ML family languages as well:

1.) Algebraic Data Types let you enforce a huge amount of correctness in your
programs simply by how you define your types.

For example, say you have a data type that represents a player's state in a
game. If the player is alive, he has a "HP" and "inventory" record. If the
player is dead, he should just be dead—HP and inventory may or may not be set
to 0 and None, respectively. In C or OOP languages, you just get a player
object/struct and you have to enforce this state logic manually, and you can
easily write a function that puts the player in an inconsistent state
(player.alive = False, but player.HP = 15). In Haskell, you can define the
player such that code that produces this kind of inconsistent state will not
compile.

Of course, you should still write tests in Haskell, but it's amazing to me
that the type system can catch the vast majority of programming errors before
your program even compiles. It takes longer to get something up and running,
but you make up for this up front cost with long term gains in
maintainability.

2.) Functional purity enforces two very useful properties:

a.) Data is never mutated by accident. This ensures you never have to look
beyond the scope of the function you're working on (or closing over, in some
cases) to know what's going on. You can then compose these functions to create
more complex programs.

b.) When you do need mutability and side effects to happen, Haskell forces you
to be very explicit about this and enforces a strict separation between "pure"
and "effectual" code. This seems arbitrary until you realize that almost all
of your errors not caught by the compiler happen because of IO. Whereas you
have complete control over the pure part of your program, IO is
nondeterministic and full of exceptions and edge cases. Separating this part
of your code makes it far easier to reason about what's happening, adding to
maintainability.

As a side note on the last point: people make the argument that this
separation makes Haskell impossible to do printf debugging. Not true—the
standard library provides ways of circumventing the type system specifically
for this reason.

3.) "Monads" and other fancy sounding abstractions can be hard, but with
practice they become as intuitive as inheritance in OOP. The real barrier to
entry is the awful, awful documentation everywhere. I make no apologies for
that: it's just really shitty and the community needs to do a hundred times
better.

~~~
SamReidHughes
> In C or OOP languages, you just get a player object/struct and you have to
> enforce this state logic manually, and you can easily write a function that
> puts the player in an inconsistent state (player.alive = False, but
> player.HP = 15).

False. In OOP you can do this using the visitor pattern. The difference is
that Haskell makes this real convenient, with its algebraic types feature
baked into the language, while OOP makes it very cumbersome.

> As a side note on the last point: people make the argument that this
> separation makes Haskell impossible to do printf debugging. Not true—the
> standard library provides ways of circumventing the type system specifically
> for this reason.

It's still far more annoying when the language is lazily evaluated and has
Haskell syntax.

~~~
clin_
> False. In OOP you can do this using the visitor pattern. The difference is
> that Haskell makes this real convenient, with its algebraic types feature
> baked into the language, while OOP makes it very cumbersome.

I don't think we're on the same page here. I meant to say that Haskell
protects against inconsistent states: you literally cannot create a dead
player with HP and Inventory records. I don't have a strong grasp on the
visitor pattern, but I'm not sure how it can be used to accomplish compile
time guarantees that the properties of an object will always be correct.

> It's still far more annoying when the language is lazily evaluated and has
> Haskell syntax.

Python:

    
    
      def f(x,y):
          print x, y
          return x + y
    

Haskell:

    
    
      f x y = traceShow (x, y) (x + y)
    

Laziness is a separate issue altogether. Debugging lazy behavior is difficult
in any language, and you would have similar problems in Python if you were
testing deeply nested generators.

That said, laziness should not be an issue if you are simply testing that
functions are correct, since most functions are pure and you will almost never
use lazy IO.

If you need to debug evaluation order or a memory leak, that's much harder,
and admitted one of Haskell's biggest weaknesses. My answer here is that you
should almost always prefer strict data structures and functions unless you
really need laziness. That's not a cure all, but it is a good policy when
programming in Haskell.

~~~
SamReidHughes
> don't think we're on the same page here. I meant to say that Haskell
> protects against inconsistent states: you literally cannot create a dead
> player with HP and Inventory records. I don't have a strong grasp on the
> visitor pattern, but I'm not sure how it can be used to accomplish compile
> time guarantees that the properties of an object will always be correct.

An example of the visitor pattern:

    
    
        class LivePlayer;
        class DeadPlayer;
    
        class PlayerVisitor {
        public:
          virtual void VisitLive(LivePlayer *p) = 0;
          virtual void VisitDead(DeadPlayer *p) = 0;
        };
    
        class Player {
        public:
          virtual void Visit(PlayerVisitor *v) = 0;
          virtual ~Player() { }
        };
    
        class LivePlayer : public Player {
        public:
          void Visit(PlayerVisitor *v) { v->VisitLive(this); }
          LivePlayer(int hp, std::vector<InventoryItem> inventory)
            : hp_(hp), inventory_(inventory) { }
          int hp() const { return hp_; }
          const std::vector<InventoryItem> &inventory() const { return inventory_; }
        private:
          int hp_;
          std::vector<InventoryItem> inventory_;
        };
    
        class DeadPlayer : public Player {
        public:
          void Visit(PlayerVisitor *v) { v->VisitDead(this); }
          DeadPlayer() { }
        };
    

This is equivalent to the Haskell code

    
    
        data Player = LivePlayer Int (Vector InventoryItem) | DeadPlayer
    

including the fact that in this example the objects are immutable.

Instead of using a case expression to pattern match over the player, you'd
have to construct a PlayerVisitor and implement the visit methods on that
type.

Things can be made a bit less cumbersome than that, for example in a language
with lambdas, you can just have the Visit method take a lambda for each
subclass, and each subclass's implementation calls one. That makes it arguably
equally convenient to use the types (with some extra parentheses), but it's
still much more annoying to define the types that way in the first place.

~~~
platz
I think even the visitor pattern isn't required here, all you need is
subclassing. Although this clutters things up more by having abstract methods
in the base class, technically that's all you need.

~~~
SamReidHughes
Sure.

------
BruceIV
I've spent the last two months wishing I'd written the project I'm working on
now in Haskell instead of C++ - the main reason? Lazy evaluation.

I'm working on developing a new algorithm, which is most easily defined as a
set of constant functions over my data structure (a DAG with about a dozen
node types). There's a fair number of places where I want shortcuts to not
calculate things if they're not needed, and with Haskell's lazy evaluation I'd
be able to just let the compiler handle most of those (the pattern matching
constructs would make my functions-by-cases cleaner to define too).

I'm doing some funny stuff with memo tables indexed by object pointers that
would be trickier to do in Haskell, but I think there's likely a library I
could leverage.

------
dustingetz
Functional programming is where you end up if you ask the question, "how can I
write better software more quickly with fewer bugs". I know of no shortcut to
grokking why FP makes this possible other than just learning how to do it.

~~~
AnimalMuppet
Cribbing someone else's answer to my similar question (a couple months ago):

Pure FP means _no_ side effects. Side effects cause your state space to
explode. (That is, no side effects means that the results of this function
depend on its inputs only. Side effects means that the results of this
function depend on its inputs, member variables of the object, file variables,
global variables, the state of various things in the OS, user input read
during the function, data read from the network, and maybe a few other things.
It's _much_ harder to understand such a function, get it working correctly,
debug it, and prove that it correctly handles all corner cases.)

The size of the program state space is your enemy, not your friend. Control it
or die. FP dramatically helps you control it.

------
nbouscal
I've always disliked the notion that Lisp or Haskell are only worth learning
because of some revelation they give you which makes you more productive when
you inevitably return to a mainstream language. Yes, there are some good
insights that both languages give you, but the real argument for using them is
that you can be more productive _in those languages_ , and that it is
reasonable to use them in a production environment for that reason. I don't
think the "return to mainstream languages" is inevitable at all, and I am very
happily using Haskell in production at my current job.

With that out of the way, what are the benefits? There are quite a few. The
following is not a complete list, but I'll try to hit the main points.

First, type safety. This is the primary argument for Haskell over something
like Common Lisp or Clojure, and it is hands-down the strongest reason I
choose to use Haskell. I used to hate static typing, because I thought static
typing meant writing a bunch of boilerplate that didn't really get you
anything and frequently got in your way. In Haskell this is not at all the
case. As it turns out, type systems have improved dramatically over the past
decades. In Haskell we have inference, so no boilerplate, and we have
incredibly powerful facilities for polymorphism, so the type system provides
real benefits. Being able to derive instances of type classes actually
drastically _decreases_ the amount of necessary boilerplate, even compared to
dynamic languages. There's a common saying in the Haskell community that if it
compiles, it probably does what you want it to. This has been my experience,
and it is incredibly pleasant.

Second, rigorous isolation of side effects. Countless programmers have
independently realized how good this is over the course of their careers.
Haskell enforces it. Knowing that a given pure function can't possibly break
something in another distant part of the application is wonderful, and
completely prevents entire classes of bugs.

Third, the community. Haskell's community is often made fun of as being overly
academic or too distant from the realities of programming, but in my
experience the community's love of abstract mathematics is a massive benefit.
One easy example is Edward Kmett's lens library. It is unabashedly abstract in
its origins, and parts of it are still a little over my head. Despite that, it
is perfectly usable without knowing the math behind it, and it is actually
_extremely useful_ in day-to-day programming. Things like functors, monoids,
and monads are often poked fun at, but they are just way too useful for me to
care. In this sense, the community is a huge asset, because people keep
churning out these useful tools that you just won't see in other languages.

Fourth, conciseness really is power. I often find myself writing one liners
that would require a dozen or more lines in the other languages I've worked
in. This frees me up to focus on the business logic, which is what actually
matters.

Parallelism is also a huge selling point, but I'll let someone else cover that
because I don't have a ton of on-the-ground experience with it.

Honestly, when I have to sum up in one sentence why I love using Haskell, it's
because it makes my job easier. At the end of the day, it's really that
simple.

~~~
solomatov
> As it turns out, type systems have improved dramatically over the past
> decades.

These kinds of typesystems were available in ML since 1973. SO they are
available to us for 41 years.

~~~
judk
I'm general, yes. The particulars have been refined.

------
coldtea
> _If you say "functional programming", please elaborate. I know all about
> function pointers in C, and I've read the docs of Python's functools module_

That's maybe 1% of functional programming, if that. And from how you write
about it, it seems like you haven't even tried to dabble with that (I mean,
merely "read the docs of the functools module"?).

But, if I may, I think the issue here is not about Haskell. Judging from the
Haskell query, and what you write about learning Vim, I think you have a
general aversion to anything that doesn't have an instant payoff and/or isn't
trivial.

Of course you can go on not knowing Haskell or Vim and 100 other things. Many
do, and don't lose much, because there are other things.

But if you go on avoiding anything that needs hard work and only offers a
future pay-off, that is, anything with a learning curve, it will certainly
hold you back. That is, if your ambition is to be a very good programmer
(which might not be).

If, on the other hand, you just want to have fun, and are content with easier
stuff, there's really no reason to learn Haskell or anything hard for that
matter.

~~~
csense
> That's maybe 1% of functional programming, if that.

I was asking where I can find the other 99%.

> And from how you write about it, it seems like you haven't even tried to
> dabble with that

Yes, I have. I use functools.partial all the time, and I've written programs
that use function pointers in C before. I'm just trying to figure out whether
"functional programming" means "passing functions around functions as objects
and the sorts of hacks you can do with args/kwargs in Python," or if there's
something more than that. For all the replies I've gotten in this thread, the
best answer I've gotten is "it's all of the above plus immutable state."

~~~
coldtea
> _Yes, I have. I use functools.partial all the time_

Well, "I read the docs" doesn't convey that. And "partial" is just, well, a
very small part of it.

> _and I 've written programs that use function pointers in C before. I'm just
> trying to figure out whether "functional programming" means "passing
> functions around functions as objects and the sorts of hacks you can do with
> args/kwargs in Python," or if there's something more than that. For all the
> replies I've gotten in this thread, the best answer I've gotten is "it's all
> of the above plus immutable state."_

Only very superficially. Passing function pointers in C is just dipping your
toes in functional programming -- if that. Let's say that those are the tip of
the iceberg -- and that the whole idea lies in the interplay of functional
concepts (much further than what people usually do in C, unless they implement
their own ad-hoc Lisp in it).

It seems like what you picked as "the best answer" from this thread is the one
that reinforced a preconceived opinion, without having to actually try
programming in a functional language.

How about this reply you got above: "Lastly, some tone stuff: Function
pointers have nothing to do with functional programming." \-- and others like
it.

------
arh68
_Stateless programming_ is what the craze is all about. A lot of programmers
grew up on C-style "x = 3;" kind of programming, so to write 500 good lines of
code without an assignment operator can be a bit like walking down the street
on your fingertips.

There is _nothing special_ about Haskell. Every single one of its qualities
have been / will be reimplemented in other languages. Do not stare at the tree
that is Haskell: talk about the forest that is PL research / features.

For example, Shen is a great mindbender close in "power" to Haskell. It's a
Lisp, it has an [inferential] static type checker, and only 2 functions in
Klambda aren't referentially transparent.

Personally I dislike Haskell's syntax and think Worse is Better, anyways. ;)

------
pekk
How do you know why Haskell is superior to whatever you're using? Haskellers
will tell you.

It should be permitted not to think Haskell is the best thing ever, but in
practice downvoting is heavily used for certain disagreements of opinion and
this is one of them.

------
Ingon
I think if the curve is too steep probably you are trying to learn too much at
a time. Focusing on small and well defined problems will help you out at least
initially. For instance I used Project Euler[1] to study some of the basics,
because the tasks there are well constrained and you cannot do too much
architecturally. You will learn the mechanics of writing small functions,
defining types, and then you can move onto something bigger, where high level
concepts are involved.

[1] [https://projecteuler.net/](https://projecteuler.net/)

~~~
quchen
I don't think ProjectEuler is very helpful for learning a language. The first
ten problems or so might be useful to learn the basic syntax, but after that
it's really just about number theory, or optimizing brute force.

If you're looking for Haskell beginner exercises, I recommend

a) implementing functions from Prelude, Data.List, Data.Tree yourself

b) doing the exercises given in RWH (even if you don't actually read the book
- just do those you understand).

RWH:
[http://book.realworldhaskell.org/read/](http://book.realworldhaskell.org/read/)

~~~
platz
exercism.io isn't bad either

------
bsamuels
One of the biggest perks of Haskell is that it has a very good static typing
system.

I wrote a blogpost awhile ago on the benefits of such a typing system, it's
kinda long but you might find it interesting:

[http://bsamuels.net/blog/2013/11/20/StaticTyping.html](http://bsamuels.net/blog/2013/11/20/StaticTyping.html)

------
michaelochurch
Haskell encourages you to think upfront about the shape of your data, because
you have to design the types upfront and your constraints are checked at
compile time. You can build a level of reliability and quality into your
software that's hard to achieve (not impossible, but rare without great
programmers) with a dynamically typed language.

There's a certain imprecision that you see with mediocre programmers. They
don't know how things work, and get used to fooling around with a certain
squishiness that's tolerated on large object-oriented projects as long as
there's one good programmer ("architect") in the batch to clean up messes.
That's good enough to get by in the business world, but not if you really want
to understand what you're doing and call yourself a true programmer.

Haskell forces you to build from the ground up, and a nice consequence of this
is that, for any type, you can inspect its pieces and get down to the bottom.
Functions will have easy-to-find type signatures and, sometimes, you can get a
good sense of what the function does from its signature.

In fact, in Haskell, the type system can be used to make assertions about
functions like "this function doesn't have any side effects" and it's trivial
to do so.

In the long term, Haskell's heavy use of immutable data structures confers
some major performance advantages as well.

Is it the right language for every purpose? No, but it's very good for many,
and it's a source of great ideas that have percolated into other languages,
like Clojure and Rust. Additionally, it will force you to think rigorously
about your data and what is happening to it.

~~~
platz
I like the balanced tone you employ here. Not a fanatic but reasonable about
the analysis.

------
bprajapa
Short Answer: The Actor Model

~~~
quchen
Haskell is not about the actor model. It is possible to use it this way, but
not what the language is about, or why you should learn it in particular.

