The most recent xkcd:
The mouseover title: "Functional programming combines the flexibility and power of abstract mathematics with the intuitive clarity of abstract mathematics."
In order to understand these jokes, you need two or three pieces of background information. As usual, the joke is unlikely to survive the explanation, but you'll be better for it :-)…
There are tasks (for example, maintaining a bank account balance) that often seem most naturally implemented with state. Pure functional programming performs these tasks, and I/O tasks such as accepting user input and printing to the screen, in a different way.The pure functional programming language Haskell implements them using monads, derived from category theory. Monads offer a way to abstract certain types of computational patterns, including (but not limited to) modeling of computations with mutable state (and other side effects such as I/O) in an imperative manner without losing purity. While existing monads may be easy to apply in a program, given appropriate templates and examples, many students find them difficult to understand conceptually, e.g., when asked to define new monads (which is sometimes needed for certain types of libraries).
If you like such things but happen not to have studied them, you could take a look at the Haskell tutorial "All About Monads", where you'll learn that
To create a monad, it is not enough just to declare a Haskell instance of the
Monad class with the correct type signatures. To be a proper monad, the
>>= functions must work together according to three laws:
(return x) >>= f == f x
m >>= return == m
(m >>= f) >>= g == m >>= (\x -> f x >>= g)
The first law requires that
return is a left-identity with respect to
>>=. The second law requires that
return is a right-identity with respect to
>>=. The third law is a kind of associativity law for
>>=. Obeying the three laws ensures that the semantics of the do-notation using the monad will be consistent.
This is still not quite enough to maintain a bank balance –
Beyond the three monad laws stated above, some monads obey additional laws. The monads have a special value
mzero and an operator
mplus that obey four additional laws:
mzero >>= f == mzero
m >>= (\x -> mzero) == mzero
mzero `mplus` m == m
m `mplus` mzero == m
It is easy to remember the laws for
mplus if you associate
mzero with 0,
mplus with +, and
>>= with × in ordinary arithmetic.
The second piece of required background information is the original pattern for the template behind "Functional programming combines the flexibility and power of abstract mathematics with the intuitive clarity of abstract mathematics."
We start with instances of the pattern "X combines the P of Q with the R of S", where Q is known for its P and S is known for its R. Some web examples:
Combines the scope of Solzhenitsyn with the mordant humour of Bulgakov.
… combines the formality of Constructivism with the lively fantasy of Surrealism.
… combines the tangy fruity flavours of cranberry with the roundness of Grand Marnier liquor.
… combines the longer racemes of L. alpinum with the denser flowers of L. anagyroides
… combines the rush of coke with the sensory bliss of Ecstasy.
Back around 1980 or so, some Lisp (or ML?) enthusiast built on this foundation a bitter little remark about the C programming language, which in the Jargon File version is “a language that combines all the elegance and power of assembly language with all the readability and maintainability of assembly language”. [Let me be explicit that this was NOT meant as a compliment.]
There are many variant versions Out There, e.g.
C combines the flexibility and power of assembly language with the user-friendliness of assembly language.
The C language combines all the power of assembly language with all the ease-of-use of assembly language.
C combines the performance of an assembly language with the expressive power of an assembly language.
The C Programming Language — A language which combines the flexibility of assembly language with the power of assembly language.
The concept is that C is barely more abstract (expressive, easy to use, readable, …) than "assembly language", which is basically a symbolic form of the lowest level of machine instructions. And for an interesting take on the issues involved, take a look at Richard Gabriel's classic essay "The Rise of 'Worse is Better'".
So the cited xkcd cartoon turns this around to complain about functional programming language like ML and Haskell (which are not "functional" in the sense of being practical or utilitarian, but in the sense of being conceptually based on mathematical functions).
In appreciating the cartoon, it also wouldn't hurt to understand what "tail recursion" is. For the purposes of the mouseover "combines" joke, all you really need to know about tail recursion is that it's something that has a special status for programs written in functional programming languages. But as Rod Johnson points out in the comments, the fact that "tail recursion" involves a recursive function call, i.e. a function that calls itself (or calls a function that calls a function … that calls the original function), is relevant to the "tail recursion is its own reward joke". The "reward" comes from the fact that "tail" recursion (a recursive call as the last thing a function does) has especially useful implementation characteristics due to potential savings in stack space (though this is actually more relevant to imperative programming languages, as I understand it).