a celestial guide

haskell.quest

a celestial guide to pure functional programming

scroll downward, traveler — the sky is alive

chapter one

The Star Map

A constellation of concepts. Each star a pure function, each line a morphism between worlds.

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"
Int String
fmap

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
m a >>= (a → m b)
polymorphic dispatch

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
take 10 ∞

coda

λ

(λx. x)

A function names its argument and returns it, unchanged. From this single gesture, an entire universe of computation unfolds.

— end of the quest, beginning of the practice —