[Haskell-cafe] there's a monster in my Haskell!

Andrew Pimlott andrew at pimlott.net
Wed Nov 1 00:14:23 EST 2006


To boost the popularity of Scheme, Felleisen has argued for renaming
"lambda" to "something cool, such as Funster".[1]  Likewise, Haskell
intimidates newcomers with the arcane term "monad".  Peyton Jones's
hopeful campaign to replace it with "warm fuzzy thing"[2] has so far
produced few results.  Inspired by Felleisen, and in the spirit of
Halloween, I offer a new alternative:  Meet "monsters", your
computational companions in the land of lazy functional programming.  To
illustrate this proposal, I present here a gentle introduction to
monsters.

Monsters come in great variety, each type having its own special powers.
But, as noted by Elmo[3], they are alike in an essential way.

All monsters are capable of devouring values:

    devour :: Monster m => a -> m a

The result of "devour x" is simply a monster that has ingested the value
"x".

Most monsters have a weakness and can be slain, liberating some ingested
values or producing some other result.  The instrument of demise varies,
as do the possible outcomes, so this function is particular to a
monster.  If SomeMonster always yields a single value upon its demise,
we would have

    slay :: SomeMonster a -> a

The compassionate (and fastidious) programmer defers the gruesome (and
messy) slaying while making use of the monster's special powers.  But
how to get at the monster's values short of that macabre act?
Fortunately, monsters gladly contribute their values towards the
creation of more monsters:

    (>>=) :: Monster m => m a -> (a -> m b) -> m b

(>>=) should be read as the monster on the left expelling values through
its rows of teeth and over its tongue at the function on the right.
(Its pronunciation is a sort of bestial hissing that is difficult to
describe; when you say it correctly, the terminal may become slightly
moist.)

Monsters range from the tame to the tumultuous, but we cannot let them
run entirely amok.  All therefore must obey the "monster laws".  For
instance, the regurgitation law states that immediately after devouring
a value, a monster expels the same value:

    devour x >>= k   ===   k x

We have still seen none of the promised special powers.  For that, we
must look at a particular monster.  The Either monster is defined as

    data Either a b = Trick a | Treat b

This monster devours Treats, but if it doesn't get a Treat, it can play
a Trick:

    playTrick :: t -> Trick t a
    playTrick t = Trick t

This monster is commonly used as follows:

    takeFood :: Food -> Either Mischief Food
    takeFood Apple     = playTrick eggHouse
    takeFood Raisins   = playTrick tpTree
    takeFood CandyCorn = devour CandyCorn

The divine among monsters is the mysterious and awesome IO.  Its powers
are vast, perhaps limitless, and beginners are taught that it cannot be
slain.  Like poisoned candy and release dates, this is of course a myth.
The pure of spirit may, after meditation at the altar of referential
transparency, cast the spell

    :: IO a -> a

(When you are prepared to call this function, its name will be
revealed.)

The ST monster can be slain without esoteric ritual:

    slay :: (forall s. ST s a) -> a

Yet philosophers whisper that there is something otherworldly about it,
a kinship with IO.  Eavesdropping on their debates, I hear the words
"phantom type", but that gives me the chills so I leave them.


[1] http://permalink.gmane.org/gmane.comp.lang.lightweight/3427
[2] http://research.microsoft.com/~simonpj/papers/haskell-retrospective/
[3] http://muppet.wikia.com/wiki/We%27re_All_Monsters


More information about the Haskell-Cafe mailing list