โ† back to index

Functors

Bartosz Milewski ยท 2015 ยท Category Theory for Programmers, Ch. 7

Prereqs: ๐Ÿž Ch1 (Category), ๐Ÿž Ch2 (Types and Functions). 7 min.

A functor is a structure-preserving map between categories. It maps objects to objects and morphisms to morphisms, so that composition and identity are preserved: fmap id = id and fmap (g . f) = fmap g . fmap f. Every container type you already use — list, optional, function — is a functor. fmap is the operation that makes it one.

What is a functor?

A functor maps one category to another. It sends each object to an object and each morphism to a morphism, preserving the wiring: if h = g . f in the source category, then F(h) = F(g) . F(f) in the target. In programming, both categories are the same (types and functions), so a functor is a type constructor plus an fmap that lifts functions inside the container. Functors also show up in unexpected places: jksoftware licenses are functors from a derivation category to an obligations category, preserving the composition of derivative works.

C a b f D F(a) F(b) F(f) F functor F maps objects and arrows, preserving structure
Scheme

The Maybe functor

Maybe either holds a value (just) or nothing. Its fmap applies the function when there's a value and passes through nothing unchanged. This is how you transform values that might not exist, without checking for null at every step.

Scheme

The List functor

Lists are functors. fmap for lists is map: apply a function to every element, preserving the list structure. This is the functor most programmers already use without knowing it.

Scheme

The functor laws

Two laws make a functor a functor. Identity: fmap id = id. Mapping the do-nothing function changes nothing. Composition: fmap (g . f) = fmap g . fmap f. Mapping a composed function equals composing the maps. If either law fails, the mapping distorts structure and isn't a functor.

Identity law a id_a F F(a) id_F(a) F(id) = id Composition law F(a) F(b) F(c) F(f) F(g) F(g∘f) F(g∘f) = F(g)∘F(f)
Scheme

The Reader functor

Functions from a fixed type r are a functor. The type constructor maps a to r -> a. And fmap is just function composition: to transform the output of a function, compose with the transformer. fmap f g = f . g. This is the Reader functor.

Scheme

Notation reference

Blog / Haskell Scheme Meaning
fmap :: (a -> b) -> f a -> f b(fmap-list f xs), (fmap-maybe f m)Lift function into functor
fmap id = id(equal? (fmap-list id xs) xs)Identity law
fmap (g . f) = fmap g . fmap f(equal? (fmap-list (compose g f) xs) ...)Composition law
Maybe a = Nothing | Just a'nothing | (just v)Optional value
[a] (List a)'(1 2 3)List type
(->) r a(lambda (r) ...)Reader: function from r
Neighbors

Milewski chapters

Paper pages that use functors

Related foundations

Foundations (Wikipedia)

Translation notes

The blog post presents functors in Haskell (typeclasses, algebraic data types) and C++ (templates, std::transform). This page uses Scheme tagged lists for Maybe and native lists for the List functor. The Reader functor is just function composition in both languages. The Const functor from the blog post is omitted here: it maps every type to the same wrapped constant and discards the function argument entirely. It matters for lenses and Yoneda, not for building intuition about what a functor does.

Ready for the real thing? Read the blog post. Start with the Haskell typeclass definition, then try the equational proofs of the functor laws.