Page 1
Category Theory for
beginnersYOW Lambda Jam 2015
@KenScambler
A B
C
Page 2
Functions
They must be good; we even have conferences for them
Page 3
A B
Set
f
functionSet
Page 4
A B
elements of A
elements of B
f
Mappings from
individual A elements
to B elements
Page 5
We like functions.
They’re simple.
They compose.
Page 8
What if we keep
the composition,
and throw away
sets & functions?
Page 9
A
Something
f
Some composable relation
between A & B Something
B
Page 11
It turns out that you
can describe most of
maths, just from this
starting point!
Page 12
Dizzyingly abstract
Page 13
Categories appear at every
step of the abstraction
continuum
Page 14
For pragmatic real-world
programmers with deadlines?
Page 15
Couple of things.
Page 16
Couple of things.
Programming = maths
Page 17
Couple of things.
Programming = maths
Programming = abstraction
Page 18
Perhaps categories
have something to
offer us after all!
Page 19
Category
Objects1.
Page 20
Category
Objects
Arrows or morphisms2.
Page 21
Category
Objects
Arrows
Domain f
dom(f)
3.
Page 22
Category
Objects
Arrows
Domain/Codomain f
cod(f)
dom(f)
4.
Page 23
Category
Objects
Arrows
Domain/Codomain
dom(g)
cod(g)
g4.
Page 24
Category
Objects
Arrows
Domain/Codomain4.
Page 25
Category
Objects
Arrows
Domain/Codomain
Composition
f
5.
Page 26
Category
Objects
Arrows
Domain/Codomain
Composition
fg
5.
Page 27
Category
Objects
Arrows
Domain/Codomain
Composition
fg
g ∘ f
5.
Page 28
Category
Objects
Arrows
Domain/Codomain
Composition
f
5.
Page 29
Category
Objects
Arrows
Domain/Codomain
Composition
f
h5.
Page 30
Category
Objects
Arrows
Domain/Codomain
Composition
f
h
h ∘ f
5.
Page 31
Category
Objects
Arrows
Domain/Codomain
Composition
Identity6.
Page 32
Category
Compose
∘ : (B C, A B) => (A C)
Identity
id : A A
Page 33
Category Laws
Associative Law
(f ∘ g) ∘ h = f ∘ (g ∘ h )
Identity Laws
f ∘ id = id ∘ f = f
Page 34
Associative law
(f ∘ g) ∘ h = f ∘ (g ∘ h )
f
g
h
(g ∘ h)
(f ∘ g)
Page 35
Associative law
(f ∘ g) ∘ h = f ∘ (g ∘ h )
f
g
h
(g ∘ h)
(f ∘ g)
Page 36
Associative law
(f ∘ g) ∘ h = f ∘ (g ∘ h )
f
g
h
(g ∘ h)
(f ∘ g)
Page 37
Associative law
(f ∘ g) ∘ h = f ∘ (g ∘ h )
f
g
h
(g ∘ h)
(f ∘ g)
Page 38
Associative law
(f ∘ g) ∘ h = f ∘ (g ∘ h )
f
g
h
(g ∘ h)
(f ∘ g)
Page 39
Associative law
(f ∘ g) ∘ h = f ∘ (g ∘ h )
f
g
h
(g ∘ h)
(f ∘ g)
Page 40
Associative law
(f ∘ g) ∘ h = f ∘ (g ∘ h )
f
g
h
(g ∘ h)
(f ∘ g)
Page 41
Identity laws
f ∘ id = id ∘ f = f
fid id
Page 42
Identity laws
f ∘ id = id ∘ f = f
fid id
Page 43
Identity laws
f ∘ id = id ∘ f = f
fid id
Page 44
Identity laws
f ∘ id = id ∘ f = f
fid id
Page 45
Sets & functions
Person
String Integer
bestFriend
length
name age
+1
(not identity!)
(not identity!)
Page 46
Sets & functions
Infinite arrows from composition
+1∘ length ∘ name
bestFriend ∘ bestFriend
bestFriend ∘ bestFriend ∘ bestFriend
+1∘ age∘ bestFriend
Page 47
Sets & functions
Objects
Arrows
Composition
Identity
Page 48
Sets & functions
Objects = sets (or types)
Arrows = functions
Composition = function composition
Identity = identity function
Page 49
Categories in code
trait Category[Arr[_,_]] {
def compose[A,B,C](c: Arr[B,C], d: Arr[A,B]): Arr[A,C]
def id[A]: Arr[A,A]
}
Page 50
Category of Types & Functions
object FnCatextends Category[Function1] {
def compose[A,B,C](c: B => C, d: A => B): A => C = {
a => c(d(a)) }
def id[A]: A => A = (a => a)}
Page 51
Category of Garden Hoses
sealed trait Hose[In, Out] {def leaks: Intdef kinked: Boolean
def >>[A](in: Hose[A, In]):Hose[A, Out]
def <<[A](out: Hose[Out, A]):Hose[In, A]
}
Page 52
Category of Garden Hoses
object HoseCatextends Category[Hose] {
def compose[A,B,C](c: Hose[B,C], d: Hose[A,B]): Hose[A,C] = {
c << d }
def id[A]: Hose[A,A] = EmptyHose
}
Page 53
Categories embody the
principle of
strongly-typed
composability
Page 55
Functors
Functors map between categories
Objects objects
Arrows arrows
Preserves composition & identity
Page 56
CF
DCategory Category
Functor
Page 57
CF
DCategory Category
Functor
CatCategory of categories
Page 58
CF
DCategory Category
Functor
CatCategory of categories
Objects = categories
Arrows = functors
Composition = functor composition
Identity = Identity functor
Page 59
Functors in code
trait Functor[F[_]] {
def map[A,B](fa: F[A],
f: A => B): F[B]
}
Page 60
Functors in code
trait Functor[F[_]] {
def map[A,B](fa: F[A],
f: A => B): F[B]
}
Objects to objects
Page 61
Functors in code
trait Functor[F[_]] {
def map[A,B](fa: F[A],
f: A => B): F[B]
}
Arrows to arrows
Page 62
Functors in code
class Functor f where
fmap :: (a b) (f a f b)
Arrows to arrows
Page 63
Composable systems
Page 64
Growing a system
Banana
Page 67
Growing a system
Bunch
Page 68
Growing a system
BunchBunch
Page 69
Growing a system
BunchBunch
Bunch
Page 70
Growing a system
BunchBunch
Bunch
BunchManager
Page 71
Growing a system
BunchBunch
Bunch
BunchManager
AnyManagers
Page 78
Using composable abstractions
means your code can grow
without getting more complex
Categories capture the essence
of composition in software!
Page 79
Look for Categories (such
as Monoids) in your
domain where you can
You can go out of your way to
bludgeon non-composable
things into a category
Page 82
Spanner
AbstractSpanner
Page 83
Spanner
AbstractSpanner
AbstractToolThing
Page 84
Spanner
AbstractSpanner
AbstractToolThing
GenerallyUsefulThing
Page 85
Spanner
AbstractSpanner
AbstractToolThing
GenerallyUsefulThing
AbstractGenerallyUsefulThingFactory
Page 86
Spanner
AbstractSpanner
AbstractToolThing
GenerallyUsefulThing
AbstractGenerallyUsefulThingFactory
WhateverFactoryBuilder
Page 88
That’s not what
abstraction means.
Page 89
Code shouldn’t know
things that aren’t needed.
Page 90
def getNames(users: List[User]): List[Name] = {
users.map(_.name)}
Page 91
def getNames(users: List[User]): List[Name] = {
println(users.length) users.map(_.name)
}
Over time…
Page 92
def getNames(users: List[User]): List[Name] = {
println(users.length) if (users.length == 1) {
s”${users.head.name} the one and only"
} else { users.map(_.name)
}}
Page 93
“Oh, now we need
the roster of names!
A simple list won’t
do.”
Page 94
def getRosterNames(users: Roster[User]): Roster[Name] = {
users.map(_.name)}
Page 95
def getRosterNames(users: Roster[User]): Roster[Name] = {
LogFactory.getLogger.info(s”When you party with ${users.rosterTitle}, you must party hard!")
users.map(_.name)}
Over time…
Page 96
def getRosterNames(users: Roster[User]): Roster[Name] = {
LogFactory.getLogger.info(s"When you party with ${users.rosterTitle}, you must party hard!")
if (users.isFull) EmptyRoster("(everyone)")
else users.map(_.name)}
Page 97
When code knows too much,
soon new things will appear that
actually require the other stuff.
Page 98
Coupling has increased.
The mixed concerns will
tangle and snarl.
Page 99
Code is rewritten each time for
trivially different requirements
Page 100
def getNames[F: Functor](users: F[User]): F[Name] = {
Functor[F].map(users)(_.name)}
getNames(List(alice, bob, carol))
getNames(Roster(alice, bob, carol))
Page 101
Not only is the abstract code
not weighed down with
useless junk, it can’t be!
Reusable out of the box!
Page 102
Abstraction is
about hiding
unnecessary
information. This
a good thing.
We actually know more about what the code
does, because we have stronger guarantees!!
Page 103
Categories show deep
underlying patterns
beneath superficially
different things
Set Set
function
Cat Cat
functor
Page 104
Just about everything
ends up being in a
category, or being one.
Page 105
There is no better
way to understand
the patterns
underlying software
than studying
Category Theory.