Category Theory made easy with (ugly) pictures

28
CATEGORY THEORY FOUNDATIONALS MADE EASY WITH (UGLY) PICTURES Ashwin Rao This is a sequel to the 3-hour course we did previously on Abstract Algebra

Transcript of Category Theory made easy with (ugly) pictures

CATEGORY THEORY FOUNDATIONALS MADE EASY WITH (UGLY) PICTURES

Ashwin Rao

This is a sequel to the 3-hour course we did previously on

Abstract Algebra

WHY ARE WE DOING THIS?• Well, some of us are trying to learn Haskell

• And there is a school of thought that says one must learn Category Theory (CT) first

• While I don’t quite agree with this, I do think a very basic intro to CT is essential

• First PreReq is the contents of Hammack’s Book of Proof – Sets, Logic, Functions etc.

• Second PreReq is the crash-course on Abstract Algebra I had done earlier: https://www.slideshare.net/cover_drive/abstract-algebra-in-3-hours

• We will combine rigorous definitions with plenty of (ugly) pictures and intuition

• After this course, you will understand the “much ridiculed” but important statement: “A monad in C is just a monoid in the category of endofunctors of C, with product ⨂ as composition of endofunctors and unit as the identity endofunctor.”

• After this course, you will also be able to make more sense of wiki pages on CT topics

• For a more detailed (and very nice) coverage of CT, Bartosz Milewski e-book hits the spot!

• I’ve also found sigfpe (Dan Piponi)’s blog posts extremely valuable.

Definition of A Category

Category C consists of: Class† of objects Obj(C) and Class of arrows Arr(C)where each arrow f has a source X in Obj(C) and a target Y in Obj(C) denoted f: X → Y

Arr(X,Y) denotes the class of arrows from source X to target Y (some authors use the term“morphism“ instead of “arrow“).

Binary composition operation ∘on arrows f and g denoted as g ∘ f∘: Arr(Y,Z) x Arr(X,Y) → Arr(X,Z)

∘ operation has two properties:

1. Associative: h ∘ (g ∘ f) = (h ∘ g) ∘ f2. Identity: For all X in Obj(C), there exists an arrow 1X in Arr(X,X) such that for all f in Arr(X,Y),

1Y ∘ f = f ∘ 1X = f

The default intuition of a category should not be as nodes and edges.Think of an object as a set, and of an arrow as a function, with special properties assigned to the sets (objects) and functions (arrows). Rely on visuals and examples to develop intuition.

† Treat the technical term “Class” as “Set” (typically refering to “set of sets”) for the purpose of this class (no pun intended!). For a precise understanding of Class versus Set, one has to refer to Zermelo-Frankel-Choice Theory which is beyond the scope of this class.

Examples of Categories

• SET – Objects are Sets, and Arrows are Functions (across the Sets)

• GRP – Objects are Groups, and Arrows are Homomorphisms (across theGroups)

• VEC– Objects are Vector Spaces, and Arrows are Linear Transformations(across the Vector Spaces)

• POS – Objects are Elements of a Partially Ordered Set, and Arrows are ≤(across the Elements)

• HASK – Objects are Haskell Types, and Arrows are Haskell Functions

WTF are Functors and Natural Transformations?

A Functor F is a “mapping” from objects and arrows of a Category C to objects and arrows of a category D with the following properties:

A. For all X in Obj(C), F(X) is in Obj(D)

B. For all f : X → Y in Arr(C), F(f) : F(X) → F(Y) is in Arr(D) such that:

1. For all X in Obj(C), F(1X) = 1F(X)

2. For all f : X → Y and g : Y → Z in Arr(C), F(g ∘ f) = F(g) ∘ F(f)

So, a Functor is a “structure-preserving“ map from one category to another.

A Natural Transformation 𝜂 from Functor F to Functor G (𝜂 : F → G) associates to every X in Obj(C), an arrow 𝜂(: F(X) → G(X) in Arr(D) such that for all arrows f : X → Y in Arr(C),

𝜂) ∘ 𝐹 𝑓 = 𝐺(𝑓) ∘ 𝜂(Don‘t panic – some (helpful) “ugly“ pictures are coming up J

The Functor CategoryIn the previous picture, collapse each of the two “objects arrays” (one for each of the two functors F and G) into a single object.

Also collapse the “arrows array” (for the natural transformation 𝜂) into a single arrow.

So you can visualize each collapsed object corresponding to a Functor, and each collapsed arrow corresponding to a natural transformation.

This “Collapsed Category” is called the Functor Category, where the objects are the Functors and the arrows are the natural transforms.

The Functor Category will be very useful as we get into advanced topics.

The Hask CategoryHask is the Haskell category where each Haskell Type is an object in Hask and each Haskell function f : X → Y (for Types X and Y) is an arrow in Hask.

Arr(X, Y) is the class of functions from X to Y. Arr(X,Y) is a Type and hence, an object in Hask.The identity function for each Type X is in the class Arr(X, X).

Functor T : Hask → Hask generates higher-order Type T X from each Type X(X-type-parametric polymorphism).

fmap generates structure-preserving functions T f : T X → T Y from f : X → Y

Functor Typeclass overloading of fmap (ad-hoc polymorphism) gives various functor instances T1,T2, …. and their fmaps.

Natural Transformation 𝜂 between T1,T2, ... take you across these higher-order Types T1X, T2X, ...

Hask examples of Functors and Natural Transformations[a] and Maybe a are examples of Functors (type-parameterized by a)

Now consider the functions maybeToList and listToMaybe

λ> :t maybeToListmaybeToList :: Maybe a -> [a]λ> :t listToMaybelistToMaybe :: [a] -> Maybe a

As you can see, maybeToList and listToMaybe are Natural Transformations.

Connecting this example to some of the pictures we drew earlier is quite helpful, IMO J

Are we ready for the M word yet?

A Monad in a Category C consists of:• Functor M : C → C• Natural Transformation 𝜂 : 1C → M (1C is the C → C identity functor)• Natural Transformation 𝜇 : M ∘ M → M (M ∘ M, abbreviated as M2, also a C → C functor)

Furthermore, we require the following so-called coherence conditions:• 𝜇 ∘ 𝑀𝜇 = 𝜇 ∘ 𝜇𝑀 (as natural transformations M3 → M)• 𝜇 ∘ 𝑀𝜂 = 𝜇 ∘ 𝜂𝑀 =13(as natural transformations M → M)

Practically, Monads let us compose f : X → M(Y) with g : Y → M(Z) into h : X → M(Z)In Haskell, ≫= ∷ 𝑀𝑎 → 𝑎 → 𝑀𝑏 → 𝑀𝑏 enables this monadic composition

𝜂 corresponds to 𝑟𝑒𝑡𝑢𝑟𝑛 ∷ 𝑎 → 𝑀𝑎 and 𝜇 corresponds to joi𝑛 ∷ 𝑀𝑀𝑎 → 𝑀𝑎

Also, the Monad Typeclass laws are simply the coherence conditions expressed in code J

Coherence Condition 1 illustrated with the [a] Monad

λ> [join [[3,2,4], [9,2]], join [[3,4], [1], [9,0,8]], join [[1,3], [7]]] – This is 𝑀𝜇[[3,2,4,9,2],[3,4,1,9,0,8],[1,3,7]]

λ> join [join [[3,2,4], [9,2]], join [[3,4], [1], [9,0,8]], join [[1,3], [7]]] – This is µ ∘ 𝑀𝜇[3,2,4,9,2,3,4,1,9,0,8]

λ> join [[[3,2,4], [9,2]], [[3,4], [1], [9,0,8]]] – This is 𝜇𝑀[[3,2,4],[9,2],[3,4],[1],[9,0,8]]

λ> join (join [[[3,2,4], [9,2]], [[3,4], [1], [9,0,8]]]) – This is µ ∘ 𝜇𝑀[3,2,4,9,2,3,4,1,9,0,8]

So, 𝜇 ∘ 𝑀𝜇 = 𝜇 ∘ 𝜇𝑀 is same as the code: join . (fmap join) == join . join

Coherence Condition 2 illustrated with the [a] Monad

λ> let ret = return :: a -> [a]

λ> ret [4,8,1,2] – This is 𝜂𝑀[[4,8,1,2]]

λ> join (ret [4,8,1,2]) – This is 𝜇 ∘ 𝜂𝑀[4,8,1,2]

λ> [ret 4, ret 8, ret 1, ret 2] – This is 𝑀𝜂[[4],[8],[1],[2]]

λ> join [ret 4, ret 8, ret 1, ret 2] – This is 𝜇 ∘ 𝑀𝜂[4,8,1,2]

So, 𝜇 ∘ 𝜂𝑀 = 𝜇 ∘ 𝑀𝜂 = 13 is same as the code: join . return == join . (fmap return) == id

Kleisli Category : A good way to conceptualize MonadsA Monad <𝑀, 𝜂, 𝜇> enables us to compose f : X → M(Y) with g : Y → M(Z) into h : X → M(Z)

To do this, we have to express h : X → M(Z) as a composition of the following 3 arrows

• f : X → M(Y) – This is the basic morphism we start with• M(g) : M(Y) → M(M(Z)) – We need this “functored“ morphism M(g) to go forward from M(Y)• 𝜇Z : M(M(Z) → M(Z) – We need this morphism 𝜇Z generated from the natural transformation 𝜇

to reduce the higher-order object M(M(Z)) to the desired object M(Z)

Now consider a Category CT (called the Kleisli Category) derived from the original Category C

• Each object of C is also an object of CT

• Each arrow X → M(Y) of C gives us the arrow X →T Y in CT (known as Kleisli arrows)• Each composition 𝜇B ∘ 𝑀 𝑔 ∘ 𝑓 in C gives us the composition 𝑔 ∘D 𝑓 in CT

Kleisli arrows compose naturally in the Kleisli Category (a good way to conceptualize Monads).

Monoidal CategoryA Monoidal Category C involves :• BiFunctor ⨂ ∶ 𝐶×𝐶 → 𝐶�

� (refered to as the monoidal product)• Object I (refered to as identity object)• Coherence conditions expressing ⨂ associativity and left/right identity laws

The idea is that ⨂ combines any two objects to yield an object (akin to Monoids).Note that ⨂ will also apply (in a natural way) on the arrows across the objects of C.

Example 1: Hask is a Monoidal Category where ⨂ is simply the Cartesian Product ofTypes (i.e., objects), which naturally produces a Cartesian Product on Functions (i.e., arrows) across those Types. Any singleton Type will behave as I.

Example 2: Recall the Functor Category we covered earlier (objects are Functors andarrows are Natural Transformations). This is a Monoidal Category where ⨂ (on objects) isthe composition of functors and ⨂ (on arrows) is the composition of natural transformations. Identity Functor will behave as I.

Monoid ObjectA Monoid Object M in a Monoidal Category < 𝐶,⨂, 𝐼 >�

� involves :

• Arrow 𝜂 ∶ 𝐼 → 𝑀 (akin to monoid unit, i.e., monoid identity element)• Arrow µ ∶ 𝑀⨂𝑀 → 𝑀(akin to monoid multiplication)

such that the following two coherence conditions apply:

• 𝜇 𝑀⨂𝜇 𝑀⨂𝑀 = 𝜇 𝜇 𝑀⨂𝑀 ⨂𝑀 = 𝑀 (akin to associativity in monoids)• 𝜇 𝑀⨂𝜂 𝐼 = 𝜇 𝜂 𝐼 ⨂𝑀 = 𝑀 (akin to left/right identity laws in monoids)

The idea is that if we peer inside the object M, 𝜇 operates like closed monoid multiplicationon elements within M, and 𝜂𝑥 in M operates like monoid identity for any x in I.

Monoid Objects in the Functor Category

Now let us consider monoid objects in the Functor Category (viewed as a Monoidal Category)

If we squint hard at the coherence conditions for the monoid object (specialized to the FunctorCategory), we see that they reduce to the coherence conditions we had stated for a Monad.

In other words, “A monad in C is just a monoid in the category of endofunctors of C, with product ⨂ as composition of endofunctors and unit as the identity endofunctor.”

This provides an alternative mental model of monads – viewing them as monoids.Let‘s use the [a] Monad in Hask to develop intuition.

λ> join [[2,3,7], [9,1], [8,6,3,9]] – Remember, join is same as 𝜇 (Monad View)[2,3,7,9,1,8,6,3,9]

λ> mconcat [[2,3,7], [9,1], [8,6,3,9]] – mconcat “mappends” the lists (Monoid View)[2,3,7,9,1,8,6,3,9]