Melbourne Scala User Group Feb 2015 KenScambler A B C Abstract maths for us Dizzyingly abstract branch of maths Abstract nonsense Programming maths Programming abstraction ID: 644292
Download Presentation The PPT/PDF document "Category Theory for beginners" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Category Theory for beginners
Melbourne Scala User Group Feb 2015@KenScambler
A
B
CSlide2
Abstract maths… for us?
Dizzyingly abstract branch of maths“Abstract nonsense”?Programming = mathsProgramming = abstraction
Really useful to programming!Slide3
The plan
Basic Category Theory conceptsNew vocabulary (helpful for further reading)How it relates to programmingCategory Theory as seen by maths versus FPSlide4
A bit of background
1940s Eilenberg, Mac Lane invent Category Theory1958 Monads discovered by GodementIn programming:1990 Moggi
, Wadler apply monads to programming2006 “Applicative Programming with Effects” McBride & Paterson2006 “Essence of the Iterator Pattern” Gibbons & OliveiraSlide5
I. CategoriesSlide6
Category
ObjectsSlide7
Category
ObjectsArrows or morphismsSlide8
Category
ObjectsArrowsDomain
f
d
om
(f)Slide9
Category
ObjectsArrowsDomain/
Codomain
f
cod(f)
d
om
(f)Slide10
Category
ObjectsArrowsDomain/
Codomain
d
om
(g)
c
od(g)
gSlide11
Category
ObjectsArrowsDomain/
CodomainSlide12
Category
ObjectsArrowsDomain/CodomainComposition
fSlide13
Category
ObjectsArrowsDomain/CodomainComposition
f
gSlide14
Category
ObjectsArrowsDomain/CodomainComposition
f
g
g
∘ fSlide15
Category
ObjectsArrowsDomain/CodomainComposition
fSlide16
Category
ObjectsArrowsDomain/CodomainComposition
f
hSlide17
Category
ObjectsArrowsDomain/CodomainComposition
f
h
h ∘ fSlide18
Category
ObjectsArrowsDomain/CodomainCompositionIdentitySlide19
Category
Compose∘ : (B C) (A B) (A C)
Identityid : A ASlide20
Category Laws
Associative Law(f ∘ g) ∘ h = f ∘ (g ∘ h )
Identity Lawsf ∘ id = id ∘ f = fSlide21
Associative law
(f ∘ g)
∘ h = f ∘ (g ∘ h )
f
g
h
(g
∘
h)
(f
∘
g) Slide22
Associative law
(f ∘ g)
∘
h = f ∘ (g ∘ h )
f
g
h
(g
∘
h)
(f
∘
g) Slide23
Associative law
(f ∘ g) ∘ h
= f ∘ (g ∘ h )
f
g
h
(g
∘
h)
(f
∘
g) Slide24
Associative law
(f ∘ g) ∘ h =
f
∘ (g ∘ h )
f
g
h
(g
∘
h)
(f
∘
g) Slide25
Associative law
(f ∘ g) ∘ h =
f
∘ (g ∘ h )
f
g
h
(g
∘
h)
(f
∘
g) Slide26
Associative law
(f ∘ g) ∘ h =
f ∘ (g ∘ h )
f
g
h
(g
∘
h)
(f
∘
g) Slide27
Associative law
(f ∘ g) ∘ h
=
f ∘ (g ∘ h )
f
g
h
(g
∘
h)
(f
∘
g) Slide28
Identity laws
f
∘ id = id ∘ f = f
f
id
idSlide29
Identity laws
f ∘ id
= id ∘ f = f
f
id
idSlide30
Identity laws
f ∘ id =
id ∘ f
= f
f
id
idSlide31
Identity laws
f ∘ id = id ∘ f =
f
f
id
idSlide32
Examples
Infinite categoriesFinite categoriesObjects can represent anythingArrows can represent anythingAs long as we have composition and identity!Slide33
Sets & functions
Person
String
Integer
bestFriend
length
name
age
+1Slide34
Sets & functions
Infinite arrows from composition+1∘ length ∘ namebestFriend
∘ bestFriendbestFriend ∘ bestFriend
∘ bestFriend+1∘ age
∘ bestFriendSlide35
Sets & functions
Objects Arrows Composition IdentitySlide36
Sets & functions
Objects = sets (or types)Arrows = functionsComposition = function compositionIdentity = identity functionSlide37
ZeroSlide38
OneSlide39
TwoSlide40
ThreeSlide41
Class hierarchy
IFruit
IBanana
AbstractBanana
BananaImpl
MockBanana
Tool
SpannerSlide42
Class hierarchy
Objects Arrows Composition IdentitySlide43
Class hierarchy
Objects = classesArrows = “extends”Composition = “extends” is transitiveIdentity = trivialSlide44
Class hierarchy Partially ordered sets (
posets)Objects = elements in the setArrows = ordering relation
≤Composition = ≤ is transitiveIdentity = trivialSlide45
World Wide Web
www.naaawcats.com
No
dogs
allowed!
www.robodogs.com
See
here
for more robots
www.coolrobots.com
BUY NOW!!!!Slide46
World Wide Web
Objects = webpagesArrows = hyperlinksComposition =
Links don’t composeIdentitySlide47
World Wide Web Graphs
Objects = nodesArrows = edgesComposition =
Edges don’t composeIdentitySlide48
“Free Category” from graphs!
Objects = nodesArrows = paths (0 to many edges)
Composition = aligning paths end to endIdentity = you’re already thereSlide49
Categories in code
trait Category[Arrow[_,_]
] { def
compose[A,B,C](
c: Arrow[B,C],
d: Arrow[A,B]): Arrow[A,C]
def
id[
A
]:
Arrow[A,A]
}Slide50
Category of Types & Functions
object
FnCat
extends 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)
}Slide51
Category of Garden Hoses
sealed trait Hose[
In, Out] {
def leaks: Int
def
kinked: Boolean
def >>[
A
]
(in:
Hose[A, In]
):
Hose[A, Out]
def
<<[
A
](out:
Hose[Out, A]
):
Hose[In, A]
}Slide52
Category of Garden Hoses
[live code example]Slide53
Categories embody the principle of
strongly-typed composabilitySlide54
II. FunctorsSlide55
Functors
Functors map between categoriesObjects objectsArrows
arrowsPreserves composition & identitySlide56
Functor laws
Composition LawF(g ∘
f) = F(g) ∘ F(f)Identity LawF(id
A) = idF(A)Slide57
C
F
D
Category
Category
FunctorSlide58
C
F
D
Category
Category
Functor
Cat
Category of categoriesSlide59
C
F
D
Category
Category
Functor
Cat
Category of categories
Objects
= categories
Arrows
=
functors
Composition
=
f
unctor
composition
Identity
= Identity
functorSlide60
C
F
D
A
B
C
g ∘
f
f
gSlide61
C
F
D
A
B
C
g ∘
f
f
g
F(A)Slide62
C
F
D
A
B
C
g ∘
f
f
g
F(A)
F(B)Slide63
C
F
D
A
B
C
g ∘
f
f
g
F(A)
F(B)
F(C)Slide64
C
F
D
A
B
C
g ∘
f
f
g
F(A)
F(B)
F(C)
F(f)Slide65
C
F
D
A
B
C
g ∘
f
f
g
F(A)
F(B)
F(C)
F(f)
F(g)Slide66
C
F
D
A
B
C
g ∘
f
f
g
F(A)
F(B)
F(C)
F(f)
F(g)
F(g ∘ f)Slide67
g ∘
f
f
g
F(f)
F(g)
F(g ∘ f)
Composition Law
F(
g ∘
f
)
= F(g) ∘ F(f)Slide68
g ∘
f
f
g
F(f)
F(g)
F(g ∘ f)
Composition Law
F(
g
∘
f
)
= F(g) ∘ F(f)Slide69
g ∘
f
f
g
F(f)
F(g)
F(g ∘ f)
Composition Law
F(
g ∘
f
)
= F(g) ∘ F(f)Slide70
g ∘
f
f
g
F(f)
F(g)
F(g ∘ f)
Composition Law
F(
g ∘
f
)
= F(g) ∘ F(f)Slide71
g ∘
f
f
g
F(f)
F(g)
F(g ∘ f)
Composition Law
F(
g ∘
f)
=
F(g) ∘ F
(
f
)Slide72
g ∘
f
f
g
F(f)
F(g)
F(g ∘ f)
Composition Law
F(
g ∘
f)
=
F(g) ∘
F(
f
)Slide73
g ∘
f
f
g
F(f)
F(g)
F(g ∘ f)
Composition Law
F(
g ∘
f)
=
F(
g
) ∘
F(
f
)Slide74
g ∘
f
f
g
F(f)
F(g)
F(g ∘ f)
Composition Law
F(
g ∘
f)
=
F(
g
)
∘
F(
f
)Slide75
g ∘
f
f
g
F(f)
F(g)
Composition Law
F(
g ∘
f)
=
F(
g
)
∘
F(
f
)
F(g) ∘ F(f)Slide76
g ∘
f
f
g
F(f)
F(g)
Composition Law
F(
g ∘
f
)
=
F(
g
)
∘
F(
f
)
F(g) ∘ F(f)
F(g ∘ f)Slide77
Identity law
F(
id
A
)=
id
F
(A)
ASlide78
Identity law
F(
id
A
)=
id
F
(A)
A
id
ASlide79
Identity law
F(
id
A
)
=
id
F
(A)
A
id
A
F(
id
A
)Slide80
Identity law
F(
id
A
)=
id
F
(
A
)
ASlide81
Identity law
F(
id
A
)=
id
F
(
A
)
A
F(A)Slide82
Identity law
F(
id
A
)=
id
F
(
A
)
A
F(A)
id
F
(A)Slide83
Identity law
F(
id
A
)
=
id
F
(
A
)
A
F(A)
id
F
(A)
A
id
A
F(
id
A
)Slide84
Terminology
homomorphismSlide85
Terminology
homomorphism
SameSlide86
Terminology
homomorphism
Same
-shape-ismSlide87
Terminology
homomorphism“structure preserving map”Slide88
Terminology
homomorphismFunctors are
“category homomorphisms” Slide89
Functors in code
trait
Functor[F[_]
] { def
map[A,B
](fa:
F[A], f: A => B
):
F[B]
}Slide90
Functors in code
trait
Functor
[
F[_]
] {
def
map[A,B](
fa
: F[A],
f: A => B): F[B]
}
Objects to objectsSlide91
Functors in code
trait
Functor
[F[_]] {
def
map[A,B](
fa
:
F[A]
,
f:
A => B
):
F[B]
}
Arrows to arrowsSlide92
Functors in code
trait
Functor
[F[_]] {
def
map[A,B]:
(A
=>
B) => (F[A] => F[B])
}
Arrows to arrowsSlide93
Functors laws in code
fa.map
(f).map(g)
==
fa.map
(g compose f)Slide94
Functors laws in code
fa.map
(a => a) ==
faSlide95
Terminology
endomorphismSlide96
Terminology
endomorphism
WithinSlide97
Terminology
endomorphism
Within-shape-ismSlide98
Terminology
endomorphism
“a mapping from something back to itself”Slide99
Terminology
endo
“a mapping from something back to itself”Slide100
Endofunctors
In Scala, all our functors are actually endofunctors
.
Type
F
Category
Category
Endofunctor
TypeSlide101
Endofunctors
Luckily, we can represent any functor in our type system as some F[_]
Type
F
Category
Category
Endofunctor
TypeSlide102
List Functor
sealed trait
List[
+
A
]
case class
Cons(head:
A
, tail:
List[A]
)
extends
List[
A
]
case object
Nil
extends
List[
Nothing
]Slide103
List Functor
sealed trait
List[
+
A
] {
def
map[
B
](f:
A => B
):
List[B]
=
this match
{
case
Cons(
h,t
)
=>
Cons(f(h), t map f)
case
Nil
=>
Nil
}
}
}Slide104
List Functor
potatoList
.map(
mashEm
)
.map(
boilEm
)
.map(
stickEmInAStew
)Slide105
List Functor
userList
.map(_.name)
.map(_.length)
.map(_ + 1)
.map(_.
toString
)Slide106
Other functors
trait Tree[
A]trait
Future[A]
trait Process[A]
trait Command[
A]X => A
(X,
A
)
trait
Option[
A
]Slide107
Functors
Fundamental concept in Category TheorySuper usefulEverywhereStaple of functional programmingWrite code that’s ignorant of unnecessary contextSlide108
III. MonoidsSlide109
Monoids
Some set we’ll call M
Compose • : M × M M
Identityid : MSlide110
Monoid Laws
Associative Law(f •
g) • h = f • (g •
h ) Identity Lawsf • id = id
• f = fSlide111
Category Laws
Associative Law(f ∘ g) ∘ h =
f ∘ (g ∘ h ) Identity Lawsf ∘ id = id ∘ f
= fSlide112
Monoids
Compose • : M × M
MIdentityid : MSlide113
Category
Compose∘ : (B C) (A B) (A C)
Identityid : A ASlide114
Category with 1 object
Compose∘ : (A A) (A A) (A A)
Identityid : A ASlide115
Category with 1 object
Compose∘ : M M M
Identityid : MSlide116
Monoids are categories
Each arrow is an element in the monoid
Only one objectSlide117
Monoids are categories
Objects
= placeholder singleton
Arrows
= elements of the monoidComposition
= •Identity = id
Only one object
Each arrow is an element in the
monoidSlide118
M
H
N
Monoid
Monoid
Monoid
homomorphism
(S
M
,
•
M
,
id
M
)
(S
N
,
•
N
,
id
N
)
Slide119
M
H
N
Monoid
Monoid
Monoid
homomorphism
(S
M
,
•
M
,
id
M
)
(S
N
,
•
N
,
id
N
)
Mon
Category of
monoidsSlide120
M
H
N
Monoid
Monoid
Monoid
homomorphism
(S
M
,
•
M
,
id
M
)
(S
N
,
•
N
,
id
N
)
Mon
Category of
monoids
Objects
=
monoids
Arrows
=
monoid
homomorphisms
Composition
= function composition
Identity
= Identity functionSlide121
M
H
N
S
M
S
N
“structure-preserving map”
Set
Set
function
h
Sets
Where
h
preserves composition & identitySlide122
Example
String length is a monoid homomorphism from (String, +, "")
to (Int
, +, 0) Slide123
Preserves identity
Preserves composition
"".length == 0
(str1 + str2).length = str1.length + str2.lengthSlide124
Monoids in code
trait Monoid
[M] { def
compose(a: M, b: M): M
def id: M}Slide125
Monoids in code
def
foldMonoid[M: Monoid
]( ms
: Seq[M]):
M = {
ms.foldLeft(Monoid
[
M
].id)
(
Monoid
[
M
].compose)
}Slide126
Int / 0 / +
i
mport IntAddMonoid._
foldMonoid[Int](
Seq( 1,2,3,4,5,6))
21Slide127
Int / 1 / *
import
IntMultMonoid._
foldMonoid[Int](Seq
( 1,2,3,4,5,6))
720Slide128
String / "" / +
foldMonoid[
String](Seq(
"alea
",
"iacta"
, "
est
"
))
”
aleaiactaest
"Slide129
Endos / id /
∘def
mash: Potato => Potato
def addOne:
Int => Int
def
flipHorizontal: Shape => Shape
def
bestFriend
: Person => PersonSlide130
A=>A / a=>a / compose
foldMonoid[
Int => Int
](Seq(
_ + 12, _ * 2, _ - 3))
(n:
Int) => ((n + 12) * 2) - 3Slide131
Are chairs
monoids
?Slide132
Chair
Composition = You can’t turn two chairs into oneIdentity =Slide133
Chair stackSlide134
Chair stack
Composition = stack them on top Identity = no chairsSlide135
Chair Stack is the
free monoid of chairs
Protip
: just take 0-to-many of anything, and you get a
monoid for freeSlide136
…almost
Real
monoids
don’t topple; they keep scalingSlide137
Monoids embody the principle of
weakly-typed composabilitySlide138
IV. Products & sumsSlide139
Algebraic Data Types
List[A] - Cons(A, List[A])
- Nil
Option[A] - Some(A)
- None
BusinessResult[A]
- OK(A) - Error
Wiggles
-
YellowWiggle
-
BlueWiggle
-
RedWiggle
-
PurpleWiggle
Address(Street, Suburb,
Postcode, State)Slide140
Algebraic Data Types
Cons(A × List[A])
+ Nil
Some(A) + None
OK(A)
+ Error
YellowWiggle
+
BlueWiggle
+
RedWiggle
+
PurpleWiggle
Street × Suburb × Postcode
×
StateSlide141
Algebraic Data Types
A × List[A] + 1
A + 1
A + 1
4
Street × Suburb × Postcode ×
StateSlide142
Algebraic Data Types
A × List[A] + 1
A + 1
A + 1
4
Street × Suburb × Postcode ×
State
isomorphicSlide143
Terminology
isomorphismSlide144
Terminology
isomorphism
EqualSlide145
Terminology
isomorphism
Equal
-shape-ismSlide146
Terminology
isomorphism“Sorta
kinda the same-ish” but I want to sound really smart
- ProgrammersSlide147
Terminology
isomorphism“Sorta
kinda the same-ish” but I want to sound really smart
- ProgrammersSlide148
Terminology
isomorphismOne-to-one mapping between two objects so you can go back-and-forth without losing informationSlide149
Isomorphism
object
object
arrowsSlide150
Isomorphism
Same as identitySlide151
Isomorphism
Same as identitySlide152
These 4 Shapes
Wiggles
Set
functions
SetSlide153
These 4 Shapes
WigglesSlide154
These 4 Shapes
WigglesSlide155
There can be lots of isos
between two objects!If there’s at least one, we can say they are isomorphic
or A ≅
BSlide156
Products
A × B
A
B
first
second
Given the product of A-and-B, we can obtain both A and BSlide157
Sums
A + B
A
B
left
right
Given an A, or a B, we have the sum A-or-BSlide158
Opposite categories
C
C
op
A
B
C
g ∘
f
f
g
A
B
C
f
op
∘
g
op
f
op
g
op
Isomorphic!Slide159
A
B
C
g ∘
f
f
g
A
B
C
f ∘ g
f
g
Just flip the arrows, and reverse composition!Slide160
A
A×B
B
A product in
C
is a sum in
C
op
A sum in
C
is a product in
C
op
A+B
B
A
C
C
opSlide161
Sums
≅ Products!Slide162
Terminology
dualAn object and its equivalent in the opposite category are
to each other.Slide163
Terminology
Co-(thing)Often we call something’s dual aSlide164
Terminology
CoproductsSums are also called Slide165
V. C
omposable systemsSlide166
Growing a system
BananaSlide167
Growing a systemSlide168
Growing a systemSlide169
Growing a system
BunchSlide170
Growing a system
Bunch
BunchSlide171
Growing a system
Bunch
Bunch
BunchSlide172
Growing a system
Bunch
Bunch
Bunch
BunchManagerSlide173
Growing a system
Bunch
Bunch
Bunch
BunchManager
AnyManagersSlide174Slide175Slide176Slide177
composeSlide178Slide179
composeSlide180
etc…Slide181
Using composable
abstractions means your code can grow without getting more complexCategories and Monoids capture the essence of composition in software!Slide182
Look for Monoids
and Categories in your domain where you canYou can even bludgeon non-composable things into
free monoids and free categoriesSlide183
VI. AbstractionSlide184
SpannerSlide185
Spanner
AbstractSpannerSlide186
Spanner
AbstractSpanner
AbstractToolThingSlide187
Spanner
AbstractSpanner
AbstractToolThing
GenerallyUsefulThingSlide188
Spanner
AbstractSpanner
AbstractToolThing
GenerallyUsefulThing
AbstractGenerallyUsefulThingFactorySlide189
Spanner
AbstractSpanner
AbstractToolThing
GenerallyUsefulThing
AbstractGenerallyUsefulThingFactory
WhateverFactoryBuilderSlide190Slide191
That’s not what abstraction means.Slide192
Code shouldn’t know things that aren’t needed.Slide193
def
getNames(users:
List[User]):
List[Name] = {
users.map(_.name)
}Slide194
def
getNames(users:
List[User]):
List[Name] = {
println(users.length
) users.map
(_.name)}
Over time…Slide195
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)
}
}Slide196
“Oh, now we need the roster of names! A simple list won’t do.”Slide197
def
getRosterNames(users:
Roster[User]):
Roster[Name] = {
users.map(_.name)
}Slide198
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…Slide199
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)
}Slide200
When code knows too much, soon new things will appear that actually require the other stuff.Slide201
Coupling has increased. The mixed concerns will tangle and snarl.Slide202
Code is rewritten each time for trivially different requirementsSlide203
def
getNames[
F: Functor](users:
F[User]):
F[Name] = {
Functor[F
].map(users)(_.name)}
getNames
(List(
alice
, bob, carol))
getNames
(Roster(
alice
, bob, carol))Slide204
Not only is the abstract code not weighed down with useless junk, it can’t
be!Reusable out of the box!Slide205
Abstraction is about hiding unnecessary information. This a good thing.
We actually know
more
about what the code does, because we have stronger
guarantees!Slide206
We’ve seen deep underlying patterns beneath superficially different things
A×B
A+BSlide207
Just about everything ended up being in a category, or being one.Slide208
There is no better way to understand the patterns underlying software than studying Category Theory.Slide209
Further reading
Awodey, “Category Theory”Lawvere & Schanuel, “Conceptual Mathematics: an introduction to categories”Jeremy Kun, “Math
∩ Programming” at http://jeremykun.com/Gabriel Gonzalez “Haskell for all”
http://www.haskellforall.com/2012/08/the-category-design-pattern.htmlhttp://www.haskellforall.com/2014/04/scalable-program-architectures.html