a celestial guide
haskell.quest
a celestial guide to pure functional programming
chapter one
The Star Map
A constellation of concepts. Each star a pure function, each line a morphism between worlds.
Hover a star
Each star reveals a chapter of the quest.
chapter two
Of Types, the compass
In Haskell, every expression has a type — a quiet declaration of what it is before what it does. The compiler reads these declarations like a navigator reads stars: a sextant for thought, a sky-chart for code.
A function from Int to String is not a routine; it is a bridge between two worlds, signed and witnessed before any traveler crosses it.
-- A bridge between worlds
describe :: Int -> String
describe 0 = "the empty set"
describe 1 = "the unit"
describe n = "a number with shape"
chapter three
Of Functors, a value in a context
A Functor is a vessel — a paper lantern carrying a value through the dark. We do not open the lantern. We merely fmap a function onto its glow, and the lantern returns, transformed and intact.
Maybe is a Functor. So is List. So is the night itself.
-- Apply within, never opening the lantern
instance Functor Maybe where
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
chapter four
Of Monads, nested contexts
If a Functor is a single lantern, a Monad is a procession of lanterns — each handed to the next, each carrying its own quiet weight of context. bind (>>=) is the gesture of passing.
It is not a fortress. It is a courtesy: a way of writing sequence without losing purity.
-- A procession of lanterns
safeDiv :: Int -> Int -> Maybe Int
safeDiv _ 0 = Nothing
safeDiv x y = Just (x `div` y)
chain = safeDiv 100 5 >>= safeDiv 2
chapter five
Of Type Classes, constellations
A type class is not a hierarchy but a constellation — types gathered by shared behavior rather than shared lineage. To be an Eq is to know how to be equal. The cosmos does not require inheritance to recognize kinship.
-- Kinship without lineage
class Eq a where
(==) :: a -> a -> Bool
instance Eq Star where
Star a == Star b = a == b
chapter six
Of Lazy Evaluation, the unfurling
Haskell does not compute what is not asked. An infinite list of primes is a perfectly civil sentence — only the first few are spoken aloud, the remainder waiting politely in the wings.
Laziness is patience as a programming discipline.
-- Infinite, but only as much as you need
primes :: [Int]
primes = sieve [2..]
where sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
first10 = take 10 primes
coda
λ
(λx. x)
A function names its argument and returns it, unchanged. From this single gesture, an entire universe of computation unfolds.