❦
being a true and faithful account of the magnificent beasts
that dwell within the lambda calculus — observed, sketched,
and humbly recorded by the naturalists of pure abstraction.
❦
Folio I · MMXXVI · Liber Monstrorum Functionalium
❧ Folio II ❧
The Bestiary Index
Six creatures dwell within the codex. Each is a concept made flesh,
a pattern with appetite. Approach them with curiosity, not fear —
they are tame to those who learn their names.
Order: Categorical
The Monad
(>>=) :: m a -> (a -> m b) -> m b
A serpent that swallows its own tail, then offers it back transformed.
Each consumption begets the next; the chain is endless and elegant.
Habitat: IO, Maybe, State, the dark forests of side-effect
Order: Mappable
The Functor
fmap :: (a -> b) -> f a -> f b
A shape-shifter whose outer form remains constant while its inner
contents transmute at will. To touch its core, one must first earn
its trust.
Habitat: Lists, Trees, every container that breathes
Order: Multi-Limbed
The Applicative
(<*>) :: f (a -> b) -> f a -> f b
A hydra whose many heads act as one, each striking in concert.
Sever a limb and another arrives, equally pure, equally lawful.
Habitat: Parsers, Validation, anywhere effects must align
Order: Combinatorial
The Monoid
mappend :: a -> a -> a mempty :: a
An elemental force that gathers all things into itself. Two grains
become one mound; one mound and a mountain remain a mountain still.
Habitat: Strings, Sums, the slow accretion of the world
Order: Genealogical
The Typeclass
class Eq a where (==) :: a -> a -> Bool
A great branching family tree, its roots tangled with abstract law,
its leaves the concrete instances that bear its name and inherit
its rites.
Habitat: Show, Eq, Ord, the polite societies of types
Order: Dormant
The Lazy Thunk
undefined :: a take 5 [1..]
A sleeping dragon coiled around an unevaluated promise. It stirs only
when something dares to demand its hoarded answer — and not a
moment sooner.
Habitat: Infinite lists, recursive structure, the patient void
❧ Folio III — The Monad ❧
Of the Serpent that Swallows Itself
Much is whispered of the Monad, and most of it
is wrong. The naturalist who first encounters this creature is told
that it is a burrito, or a box, or a programmable semicolon —
each comparison less faithful than the last. The truth is plainer
and stranger: the Monad is a serpent that ties together what would
otherwise unravel.
It binds. That is its single, tireless act. Given a value cradled
in some context, and a function that knows how to extend that
context, the Monad weaves them into a single uninterrupted thread.
From this small motion the whole fabric of effectful computation
is woven — input, output, failure, choice, time itself.
✎Field observation, recorded in the margins:
greet :: IO ()
greet = do
putStr "What is your name? "
name <- getLine
putStrLn ("Hello, " ++ name ++ ".")
Each <- is a bite. The serpent
consumes the result of the prior action and extends the chain by
one more link. To the untrained eye it appears as an imperative
sequence; to the naturalist it is a single composition, pure and
whole, merely described in the order of its unfolding.
✎The three laws by which the creature lives:
-- Left identity
return a >>= f ≡ f a
-- Right identity
m >>= return ≡ m
-- Associativity
(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
Honour these three laws and the Monad is your steadfast companion.
Violate them and it will eat its tail forever, returning nothing
but the bitter taste of its own ill-formed shape.
❧ Folio IV — The Functor ❧
Of the Shape-Shifter that Keeps its Skin
The Functor is the kindest beast in
the codex. It asks only one favour: do not change my outer
form. Within that single rule, it permits the naturalist any
liberty — reach inside, transform what you find, and return
a creature with the same silhouette but a wholly new soul.
The signature it offers is a small contract:
fmap :: (a -> b) -> f a -> f b.
The container f never changes its
kind. A list remains a list; a tree remains a tree; a Maybe remains
a Maybe. The contents alone are the field of play.
✎An instance, recorded in the field:
instance Functor Maybe where
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
Two laws bind the Functor as surely as gravity binds a stone:
identity (fmap id ≡ id) and
composition
(fmap (g . f) ≡ fmap g . fmap f).
Together they ensure the shape-shifter never loses its way home,
no matter how many transformations it endures.
❧ Folio V — Lazy Evaluation ❧
Of the Dragon who Sleeps until Demanded
The Dragon of Lazy Evaluation does not
wake for idle curiosity. It sleeps upon its hoard of unevaluated
expressions — thunks, by the proper name — and stirs
only when something dares to demand their value. To call
it is to enter a contract: ask, and you shall receive; ask not,
and the dragon dreams on.
This is no slothful trait but a marvellous economy. Whole infinities
may be inscribed in the codex without ever filling its pages,
because no page is read until needed. Behold the catalogue of
natural numbers, complete and infinite, fitting in a single line:
✎The infinite list, summoned only in part:
naturals :: [Integer]
naturals = [1..]
primes :: [Integer]
primes = sieve [2..]
where sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
take 10 primes
-- ⇒ [2,3,5,7,11,13,17,19,23,29]
The dragon stirred only ten times. The remaining infinity continues
to sleep, untouched, untaxed, untethered to any clock. Such is the
gift of laziness: every expression is a promise, and only the kept
promises cost anything at all.
⚠A naturalist's caution: the dragon hoards thunks even
when you do not need them. In long-running computations, an
unspent promise can grow into a heavy tail. The wise tame their
beast with strictness annotations — seq,
!, deepseq —
rousing the dragon at chosen moments, lest the hoard topple.
❧ Folio VI · The Colophon ❧
█
Thus ends our brief survey of the bestiary. The creatures recorded
herein are neither caged nor tamed; they roam the type system as they
have always roamed, indifferent to the naturalists who chronicle them.
Yet to know their names is to walk among them with a small but
necessary courage.
✎The monster's footprint, left for those who follow:
main :: IO ()
main = do
putStrLn "Here be Monads."
let beasts = ["Monad", "Functor", "Applicative",
"Monoid", "Typeclass", "Lazy Thunk"]
mapM_ (putStrLn . ("· " ++)) beasts
putStrLn "— Liber Monstrorum Functionalium —"
Explicit Liber Monstrorum Functionalium. — copied by an unknown hand, MMXXVI —