haskell.day
A cinematic exploration of functional programming
The Lambda Calculus
In the beginning, there was the lambda. Alonzo Church gave mathematics a notation so elegant it would take decades for the world to understand its power. A single Greek letter that could express any computable function.
Haskell inherited this legacy and made it breathe. Every function, every computation, every transformation of data traces its lineage back to that solitary symbol: λ.
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
The Type System
If lambda calculus is the soul of Haskell, the type system is its skeleton. Hindley-Milner type inference reads your intentions before you state them, catching contradictions the way a careful editor catches plot holes in a manuscript.
Types in Haskell are not constraints imposed upon the programmer. They are a dialogue between human intention and mathematical truth. Every type signature is a theorem; every function body, its proof.
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
The Monad
The monad is perhaps the most misunderstood character in all of computer science. Not because it is complex, but because it is so simple that our minds, trained on imperative thinking, struggle to accept its elegance.
A monad is a design pattern for composing computations. It says: here is a value in a context. Here is a way to chain operations that respect that context. That is all. IO, Maybe, Either, List — each tells a different story through the same narrative structure.
class Applicative m => Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
Purity and Laziness
Haskell's purity is not asceticism — it is clarity. When a function promises to map A to B, it does exactly that. No hidden state mutations, no surprise side effects, no secret negotiations with the outside world.
And laziness — Haskell's most radical proposition — means that computation happens only when its result is needed. Infinite data structures become not just possible but natural. A lazy list of all prime numbers simply exists, waiting to be consumed one element at a time.
primes :: [Integer]
primes = sieve [2..]
where sieve (p:xs) =
p : sieve [x | x <- xs, x `mod` p /= 0]
haskell.day
Avoid success at all costs.