Category Theory for Functional Programmers Functors, Natural Transformations, Adjunctions
Total Page:16
File Type:pdf, Size:1020Kb
Category Theory for Functional Programmers Functors, Natural Transformations, Adjunctions Nick Hu University of Oxford [email protected] ABSTRACT GROUNDWORK Category Theory is a very abstract theory of mathematical A category 풞 is defined by a collection of objects, ob (풞), and structure, which has strong links with functional program- a collection of morphisms, hom (풞), which are maps between ming. In this essay, I explore basic category theory construc- objects. A morphism 푓 has a domain dom (푓) and a codomain tions using insights from functional programming to provide cod (푓), which are objects, and 푓∶ 푋 → 푌 or equivalently 푓 examples and motivation. The categorical triad of functori- 푋 → 푌 is written to denote that 푓 is a morphism with ality, naturality, and universality (adjunction) is ubiquitous domain 푋 and codomain 푌. in mathematical spheres, and I aim to cover it in a brief yet elucidating manner, unburdened from complex heavy rigour Categories must also satisfy the following conditions: present in almost any graduate text on category theory. • for each object 푋, there exists a morphism idX ∶ 푋 → 푋; • for any two morphisms 푓∶ 푋 → 푌, 푔∶ 푌 → 푍, there exists a composite morphism 푔 ∘ 푓∶ 푋 → 푍. INTRODUCTION Composition must be associative, and identity morphisms must act as a unit to composition, as shown in the following Categories are the essence of composition, category theory commutative diagrams: yields a ubiquitous language interesting to logicians, philoso- 푓 푓 phers, computer scientists, mathematicians, and physicists 푋 푌 푋 푌 alike. In fact, Baez (2010) goes on to suggest that often idX idY different concepts in wildly different disciplines are actually 푓 푓 merely different exposition for ‘the same’ phenomena. 푋 푌 For computer science especially, category theory ‘gives a In a category, identity morphisms are necessarily unique. precise handle on important notions such as compositional- The category which we are primarily interested in is Hask, ity, abstraction, representation-independence, genericity and which has Haskell types as its objects and Haskell functions more’ (Abramsky and Tzevelekos 2010). as its morphisms. More fundamental still, is that category theory attempts to To see that this forms a category, recall the polymorphic address and challenge the age-old problem of what formal function: ‘equality’ means and what is actually desirable — notions of equality from set theory are fraying at the edges in modern id :: a -> a mathematics, as seen in the new and fast-moving field of id x = x Homotopy Type Theory. then if any type A is an object of Hask, its identity mor- Certain categories, which will be touched on later, suffice to phism is given by the monomorphic specialisation of id to model computation and logic; a prime example of this is the id :: A -> A. relationship between the simply-typed 휆-calculus, intuitionis- Morphisms compose via ordinary Haskell function composi- tic logic, and Cartesian Closed Categories, as stipulated by tion (post monomorphic specialisation): the Curry-Howard-Lambek correspondence. (.) :: (b -> c) -> (a -> b) -> a -> c Much of this essay is inspired by Bartosz Milewski’s excellent (.) g f = \x -> g (f x) book on Category Theory for Programmers (2017), and that is where the title comes from — a lot of this work can be For Hask to really be a category, ‘fast and loose reasoning’ regarded as my personal distillation and insights from reading will be used to conveniently pretend that Haskell functions it, presented as briefly as I could justify. are total, and ignore concerns arising from ⊥ (Danielsson et al. 2006). Throughout this essay, I will make assertions in bold — the reader may treat these assertions as exercises to justify. These functions are sufficient to establish Hask as a category. Nick Hu In category theory, we generally don’t care about what the is as translations between different representations of the objects are, but instead how they interact with each other same data — a linked list can be traversed and the contents (via morphisms). dumped into an array, and similarly a linked list can be built from the contents of an array. Other examples of a category include: • Set, with objects as sets and morphisms as set-functions between them; LIMITS AND COLIMITS • Pos, with objects as partially ordered sets and morphisms In a category 풞, a terminal object 1 is an object where every as monotone maps; other object 푋 in 풞 has a unique morphism 휄푋 targeting it • the category of a specific preordered set (푋, ≺), with 휄푋 objects 푥 ∈ 푋 and morphisms 푥 → 푦 ⟺ 푥 ≺ 푦;1 (i.e. ∀푋 ∈ ob (풞) ⋅ ∃! 휄푋 ⋅ 푋 → 1). Dually, an initial object 0 • the category of a specific monoid (푀, ⋅, 푒), with a single is an object where every other object 푋 in 풞 has a unique object and morphisms 푚 ∈ 푀. The identity morphism is morphism !푋 originating from it. Initial and terminal objects given by 푒, and composition is given by ⋅. If instead we are unique up to unique isomorphism. have a group, then all of the morphisms are isomorphisms; In Set, ∅ is initial, and the singleton set {∗} is terminal. • Cat, with objects as categories2 and morphisms as func- To see why, consider the number of functions 푓푋 ∶ ∅ → 푋; tors; there is only one such function: the empty function. For any • 풞op, the dual category to 풞 with the direction of its set 푋, there is only one function 푓푋 ∶ 푋 → {∗}: the constant morphisms reversed — 푓∶ 푋 → 푌 ∈ hom (풞) ⟺ 푓∶ 푌 → op op function. This can be checked by considering that the number 푋 ∈ hom (풞 ). If 풞 = 풞 then 풞 is self-dual; |푋| of functions from two sets 푋 and 푌 is |푌| — for the initial • Rel, with objects as sets and relations as morphisms; 0 Rel is self-dual because relations are symmetric whereas object we have |푋| = 1, and for the terminal object we have |푋| functions are not. 1 = 1. The category Set is very important, and new concepts will In Hask, the initial object is a type Void which has no con- frequently be introduced via Set. structors. The unique morphism associated to it is: absurd :: Void -> a Isomorphism As Void has no inhabitants, there is no meaningful definition In a category 풞, if there is a morphism 푓∶ 푋 → 푌, and for this function, just as the empty set-function has no mean- a morphism 푔∶ 푌 → 푋 such that the following diagram ingful map. The unit type, (), is terminal, and the unique commutes: morphism associated to it is: 푓 unit :: a -> () id 푋 푌 id X 푔 Y unit _ = () then 푋 and 푌 are isomorphic, and 푓 and 푔 are isomorphisms. or equivalently unit = const (). The problem of equality is a far-ranging one, but the usual def- A useful, but naïve, intuition for the relationship between inition of extensional equality (or even intensional equality) is Hask and Set is to treat each type as a set with cardinality often too strict. In category theory, isomorphism is commonly equal to the number of inhabitants of that type. Void has no regarded as a sufficient notion of ‘sameness’; often, category inhabitants, and thus corresponds to the empty set. Similarly, theorists come up with universal constructions establishing unit has a single inhabitant () — it is unimportant what some property that is ‘unique up to unique isomorphism’ that is, because all singleton sets are trivially canonically (canonical isomorphism). isomorphic. An analogy from programming is the abstraction barrier: in A product of two sets 푋 and 푌 is traditionally given general, we don’t really care how an interface is implemented by {(푥, 푦) ∣ 푥 ∈ 푋, 푦 ∈ 푌} — the Cartesian product con- given that it fully satisfies the specification. A stack can be struction. The product can alternatively be defined to be implemented using a linked list, a heap, or an array, and {(푦, 푥)|푥 ∈ 푋, 푦 ∈ 푌}, or even {(푥, ∅, 푦) ∣ 푥 ∈ 푋, 푦 ∈ 푌}. As correct implementations will behave indistinguishably in the long as our theorems about products of sets are aware of abstract — in the concrete, implementations will behave which representation is chosen, they still hold, and indeed differently, but beyond the concern of rationally reasoning these representations are isomorphic to each other. about correctness. Another way of viewing the isomorphisms Categorically, this implementation detail can be abstracted 1Identity morphisms exist due to the reflexivity of the ordering relation, away, and instead a product is defined in terms of an abstract and composite morphisms from transitivity. 푋 푌 2 interface: a product of two objects and is an object Which are small — 풞 is small when its collections of objects and 푋 × 푌 휋 ∶ 푋 × 푌 → 푋 morphisms are set-sized. Cat itself is large, but otherwise we will only along with projection maps 1 and consider small categories. 휋2 ∶ 푋 × 푌 → 푌. Category Theory for Functional Programmers 푖 푖 However, this definition is insufficient — the Cartesian 푋 1 푋 + 푌 2 푌 set product 푋 × 푌 × {0, 1} as a categorical product of objects 푋 and 푌 in Set, with projection maps 휋 (푥, 푦, 0) ↦ 푥, [푓,푔] 1 푓 푔 휋1(푥, 푦, 1) ↦ 푥 (and similarly for 휋2) satisfies this definition, but this ‘product’ contains an extra bit of information. We 푍 want our notions of product to be isomorphic to each other, In Set, the coproduct of 푋 and 푌 is given by the disjoint but there is no canonical mapping between the Cartesian set union 푋 ⊎ 푌. In Hask, coproducts of types are sum types products 푋 × 푌 → 푋 × 푌 × {0, 1}. But the reverse map exists tagged by constructors; the canonical example: canonically by simply forgetting the extra bit of information; in general, this corresponds to the existence of a morphism data Either a b = Left a | Right b in Set from ‘products’ with too much information, to the is the coproduct of polymorphic types a and b, with con- traditional Cartesian product.