Monday, February 09, 2009

Haskell comprehension measured through WTF/min

The top compliment I can give to Real World Haskell is that it manages to finally teach me the aspects of Haskell programming that I previously assumed to be both impenetrably complicated and useless. As I read I'm also reminded of what it was like when I first tried to comprehend Haskell code. I've concluded that the most noticeable sign of greater Haskell comprehension is a noticeable drop in my WTF/min when I'm figuring out a given code example.

WTF/min is "WTFs per minute". According to a highly-linked picture, this unit is "the only valid measurement of code quality" and it's determined through code reviews. My initial experiences of Haskell definitely exhibited high WTF/min. The following are some of the past Haskell-related thoughts I can recall having at one time or another.
  • Infinite lists like [1..]? WTF? Oh, lazy evaluation, right.
  • Functions defined more than once? WTF? Oh, each declaration pattern matches on a different set of parameters. It's like method overloading.
  • The underscore character has nothing to do with this problem domain but it's being matched against. WTF? Oh, it matches anything but discards the match.
  • Why is the scoping operator "::" strewn throughout? WTF? Oh, it's being used for types, not scopes.
  • Even a simple IO command like "putStrLn" has a type? WTF is "IO ()"? Oh, it's an expression with IO side-effects that evaluates to the value-that-is-not-a-value, ().
  • WTF? What is this ubiquitous 'a' or 't' type everywhere? Oh, it's like the type parameters of generics or templates.
  • Functions don't need "return" statements? WTF? Oh, all functions are expressions anyway.
  • WTF is going on with these functions not being passed all their parameters at once? Oh, applying a function once produces another function that only needs the rest of the parameters. That'll be helpful for reusing the function in different contexts.
  • This function definition doesn't have any parameters at all, and all it does is spit out the result from yet another function, a function that itself isn't being passed all the parameters it needs. WTF? Oh, "point-free" style.
  • Now I understand all those -> in the types. But WTF is this extra => in front? Oh, it's sorta like a list of interfaces that must be met by the included types, so the code is tied to a minimal "contract" instead of a particular set of explicit types. That's good, but how would I set those up?...
  • Ah, now this I'm sure I know. "class" and "instance" are easy. WTF?! How can that be it? Just more functions? Can't I store structured information anywhere? Oh, tuples or algebraic data types.
  • I like the look of these algebraic data types with the "|" that I know from regular expressions. Unions and enums in one swell foop. WTF? How do I instantiate it? Oh, what appear to be constituent data types are actually constructor functions.
  • After a value has been stuffed into the data type, how can my code possibly determine which data type constructor was used? WTF? Oh, just more pattern-matching.
  • WTF? Record syntax for a data type declaration results in automatic accessor functions for any value, but we use these same function names when we're creating a new record value? Oh.
  • I've acquainted with map and filter. WTF is foldr and zip and intercalate? Oh, I'll need to look over the standard list functions reference.
  • What's this "seq" sitting in the middle of the code and apparently doing jack? WTF for? Oh, to escape from laziness when needed.
  • WTF? How can a function name follow its first argument or a binary operator precede its first argument? Oh, `backticks` and (parentheses).
  • How come there's all these string escapes in the flow of code? W...T...F? Oh, lambda. Cute.
  • I've always been told that Haskell is heavily functional and pure. WTF are these do-blocks, then? Oh, monads. Wait, what?
  • Functor, Monoid, MonadPlus, WTF? Oh, more typeclasses whose definitions, like that of monads, enable highly generalized processing.
  • A way to gain the effects of several monads at once is to use "transformers"? WTF? Oh, when a transformer implements the monad functions it also reuses the monad functions of a passed monad.
  • Finally...I know that the ($) must be doing something. But what? Why use it? WTF? Oh, low-precedence function application (so one can put together the function and its arguments, then combine them).