At OSCON last week, my favorite tutorial was Simon Peyton-Jones’s A Taste of Haskell (A Taste of Haskell presentation materials (PDF)). I’ve dabbled with the language before (and pair programmed with Audrey Tang once to find and fix a bug in Pugs), but I’ve never really felt comfortable with the language.
It’s nice to report that function composition actually makes sense to me now. (At Foo Camp, I spent ten minutes explaining to Brian O’Sullivan why and how it tripped me up every other time I tried to figure it out, so hopefully Real World Haskell will smooth out that path for other people.
Most of my work these days is in C, though. As a junior language designer, I spend a lot of time considering the differences between languages (and, yes, rarely at the syntactic level).
I sat next to Nat Torkington at the tutorial. He kept rubbing his temples. At one point I leaned over and said, “The interesting thing about Haskell is that its functions only take one argument.” He turned green.
In all seriousness, well-factored Haskell code resembles well-factored Smalltalk code: if you have functions (or methods) longer than a handful of lines, you’re probably doing too much. Lower level languages such as C rarely give the opportunity for composition and abstraction that you can get out of functional languages. The presence of pure functions–functions which never change global state and which return the same output for the same input–is also immensely important.
It’s actually the combination of the two features which give these languages such power. When Haskell forces you to mark impure functions explicitly, it gives you tools to isolate behavior which can change global state in the smallest possible scopes, and prevents you from composing impure and pure code together accidentally. When Haskell lets you compose functions into larger functions, not only does it help you write code more concisely, but it provides well-defined units of behavior which work along well-defined and isolated boundaries.
If you can get your program into a succinct form where the important features of your algorithms are in isolated units, you can use tools such as Quick Check to test their behavior in isolation.
The desire to test small, individual pieces of a large pile of C code has gone further to convince me of the benefits of Haskell and similar language than anything else. I’m tired of keeping track of side effects and global state and trying to figure out exactly what I have to mock up before I have to tackle the work of linking and exporting symbols and calling a C function from a shared library.
I just don’t know how to write a concurrent-safe garbage collector in Haskell to use in a large, cross-platform project written otherwise mostly in C.

Here's the first part of the video: http://blip.tv/file/324976
Haskell is _too_ functional for me personally.
I rather enjoy a hybrid functional/procedural language called Ruby. You may have heard of it. It's a pleasure to work with.
It shouldn't be harder to write a garbage collector in Haskell. You might be bothered a bit that the Haskell code will run in a little heap managed by the garbage collector of your favorite Haskell implementation, but you can tightly control the size of that heap, and use Foreign.Ptr to do whatever you like to the C heap living in the rest of memory. I'll get there eventually, as I rewrite some toy interpreters to rely less and less on features of the host language.
I'm guessing that last statement was intended to be humorous, but if you're actually having trouble figuring something out, try #haskell on freenode irc. Incredibly helpful people there--one of the best things about the language, actually.
@msouth, thanks for the reminder. Haskell is probably a no-go for this project for various reasons completely unrelated to the quality of the technology, but it's a tempting thought. (The main issues are deployment and finding future maintainers, though the latter is much less of an issue as I'm only doing this because we can't find anyone else.)
Haskell is _too_ functional for me personally.
Ruby isn't really functional, though it supports a subset of the features of those languages, it lacks referential transparency which is absolutely essential to functional languages (or at least a clear separation between pure and impure worlds). Thus chromatic wouldn't get such an automatic fine division of the code with Ruby..
And using anonymous functions or higher order function isn't really natural beyond the "block".
Beside that static typing and inference makes quite a difference between Ruby and Haskell...
And GHC is much faster than Ruby.
--
Jedaï