There are more than a couple of meatless posts on the net about how the magical (not at all) functional programming paradigm is entirely different (no it isn't) from everything you are used to, and how will it save the world (no it won't).

So let's try to approach Haskell, which is the 800-pound gorilla in FP (functional programming) land, from a practical angle, without empty buzzwords. If you think that this article also lacks meat, well, you are wrong because I am right, but nevertheless slap me in the face.

I will intentionally remain in shallow waters to be easily digestible by the broadest possible audience.

Static type system with type inference

Most programmers thinkink about static typing imagine something like this:

    Foo* foo = new(Foo);

Usually when coders argue about wether static or dynamic typing is teh sh*t, they contrast the dynamically typed languages with C++/Java school of static typing (see above). Sacrificing some sophistication the usual conclusion can be reduced to "static typing can catch more bugs but you have to type more" (let's not go into unit testing now). If that's what you tought too, let me introduce you the Hindley-Milner type inference. Basically with the help of it, the compiler can type check your code without requiring you to annotate your types in even one place (I lied, in rare cases, it may be required).

And no, Google's new language, Go does not have type inference, at least nothing comparable to what you can find in Haskell. What the Go evangelists try to sell as type inference is a very little subset of (full) type inference. The Go way:

func nonsense(a int, b string) int {    // <- You have to annotate type or compilation fails.
    c := 42 // <- "Initialization and declaration" which is being sold as type inference
    return a + c
}

The Haskell way:

nonsense a b = let c = 42 in a + c

That Haskell snippet will compile. What will be the type of it? You can query it by typing ":t nonsense" in GHCi

> :t nonsense
nonsense :: Num a => a -> t -> a

That type signature basically means: nonsense is a function, with two arguments, first is a, which can be any type, as long as that given type can be used as a number (is an instance of type class Num. Don't confuse type classes with Javaish classes, they are more like interfaces). The second argument can be any type, without restriction. Why? Because we did not use it! The return value has the same type as the first argument. This part can be quite tricky to nonhaskellers, because return type polymorphism is very rare in mainstream languages.

As you can see, what we have here is the best of both worlds: compile time type checking without the requirement of annotating types by hand. Of course, type annotation is useful for humans, but the Haskell compiler doesn't really care about it, he is clever enough to figure this out. In fact, a lot of times I (and I suspect others too, but I can't speak for them) I write the function without type annotations, ask GHCi for the type signature and paste that into the source file to help others and my 2 months older version of me understanding the code.

Generics without breaking a sweat

As mindful readers may have already noticed in the above Haskell snippet, in Haskell you write generic code by default. You don't have to learn a template language (there is a thing called Template Haskell but that is another story), you don't have to buy a 24 inch monitor to write generic function signatures. That is the default and it comes for free.

Syntax without clutter

One thing I noticed while learning Haskell, that the authors have a great sense of beauty. This can be generally said about the language as a whole, but it can be most easily seen when looking at the syntax. Here are a couple of constructs side by side with the Go version, as that is a language I used directly before Haskell thus I hopefully make no errors.

// Switch case

// Go
a := 20
switch a {
    case 10:
            return "It's ten!"
    case 20:
            return "It's not ten :("
}
// Haskell
let a = 20
in case a of
    10  -> "It's ten!"
    20  -> "It's not ten :("
// Anonymous function

func (a, b int) int {
    a + b
}
\a b -> a + b
// Looping: transform a list/array

// Go
a := []int{1,2,3,4,5,6,7,8,9,10}
f := func(a int) int {
    return a+1
}
b := []int{}
for _, v := range a {
    b = append(b, v)
}
return v
// Haskell
let a = [1..10]
    f = (+1)
map f a

The differences really add up. There are some outrageous claims on the net about how much you can save with functional programming in terms of line count, but I think a good estimate is that you can at least halve the LOCs.

REPL

Haskell is amongst the few statically typed languages what you can use interactively. GHCi is the Haskell compiler, and despite being a not too mainstream language, it is the Haskell platform is a breeze to use, even on Windows, its a one click install, and you can double click on any hs files and GHCi starts. GHCi is an incredible productivity boost. Just to name a few cool features: :t gives back the type of any expression, :i will display information about the given type, you can set GHCi to clock all expressions (display the milliseconds spent calculating the expression). The possibilities are endless, really.

Type signatures are telling

The information dense type signature of Haskell functions allow us to effectively search for a function by approximate type with the help of a tool like Hoogle.

Conclusion

The general consensus on Haskell is that it's impractical. I think that opinion mainly stems from old experiences. I agree that it's still rough around some edges: I am particularly worried about the lack of stack traces. The thought of running it on production servers and not seeing the source of an exception frankly scares the sh*t out of me. But as a language it is very well designed, especially compared to the current mainstream languages.