Category Theory forBeginners Your data structures are made of maths! Melbourne Scala User Group Mar 2015 @KenScambler
Data structures More andmore “logical” Less low-level memory/hardware connection More and more support for immutability We can use maths to reason about them! Category Theory can reveal even deeper symmetries
Integers as types? Wecan actually use integers to represent our types! The integers correspond to the size of the type
sealed trait Holiday caseobject Christmas extends Holiday case object Easter extends Holiday case object AnzacDay extends Holiday Sums in code
sealed trait Holiday caseobject Christmas extends Holiday case object Easter extends Holiday case object AnzacDay extends Holiday 1
sealed trait Holiday caseobject Christmas extends Holiday case object Easter extends Holiday case object AnzacDay extends Holiday 11
sealed trait Holiday caseobject Christmas extends Holiday case object Easter extends Holiday case object AnzacDay extends Holiday 11 1
sealed trait Holiday caseobject Christmas extends Holiday case object Easter extends Holiday case object AnzacDay extends Holiday 3
sealed trait Opt[A] caseclass Some[A](a: A) extends Opt[A] case class None[A] extends Opt[A]A + 1
Functions “with noarguments” are tacitly from a singleton type such as Unit Singleton types carry no information.
sealed trait List[+A] caseclass Cons[A](h: A, t: List[A]) extends List[A] case object Nil extends List[Nothing] A
sealed trait List[+A] caseclass Cons[A](h: A, t: List[A]) extends List[A] case object Nil extends List[Nothing] A L(A)
sealed trait List[+A] caseclass Cons[A](h: A, t: List[A]) extends List[A] case object Nil extends List[Nothing] A × L(A)
sealed trait List[+A] caseclass Cons[A](h: A, t: List[A]) extends List[A] case object Nil extends List[Nothing] A × L(A) 1
sealed trait List[+A] caseclass Cons[A](h: A, t: List[A]) extends List[A] case object Nil extends List[Nothing] 1 + A × L(A)
Expanding a list… L(a)= 1 + a L(a) = 1 + a (1 + a L(a)) = 1 + a + a2 (1 + a L(a)) … = 1 + a + a2 + a3 + a4 + a5…
Expanding a list… L(a)= 1 + a L(a) = 1 + a (1 + a L(a)) = 1 + a + a2 (1 + a L(a)) … = 1 + a + a2 + a3 + a4 + a5… Nil or 1-length or 2-length or 3-length or 4-length etc
What does itmean for two types to have the same number?
There can belots of isos between two objects! If there’s at least one, we can say they are isomorphic or A ≅ B
Products in CT A× BA B first seco nd trait Product[A,B] { def first: A def second: B }
Sums in CT A+ BA B Left Right sealed trait Sum[A,B] case class Left[A,B](a: A) extends Sum[A,B] case class Right[A,B](b: B) extends Sum[A,B]
A A×B B A product inC is a sum in Cop A sum in C is a product in Cop A+B B A C Cop
Tightening the definitions A× BA B first seco nd × × trait ProductPlusPlus[A,B] { def first: A def second: B def banana: Banana def brother: BluesBrother }
A × BAB first seco nd × × Does that still count as A × B?
A × BAB first seco nd × × No way!
A × BAB first seco nd × × Umpire theA someB trait Umpire { def theA: A def someB: B }
A × BAB first seco nd × × Umpire theA someB trait Umpire { def theA: A def someB: B } unique∃
(a, b,a b Umpire traitUmpire { def theA: A = a def someB: B = b } , ) not actually unique Instances
Requiring a uniquearrow from a 3rd object that independently knows A and B proves that there’s no extra gunk.
What if Umpirehas special knowledge about other products?
A × BAB first seco nd Umpire theA someB trait Umpire { def theA: A def someB: B def specialOtherProd: (A,B) }
We need toknow nothing about the object other than the two arrows!
PA B ??? ? ? unique∃ Forall objects that 1) have an arrow to A and B 2) there exists a unique arrow to P
SA B ??? ? ? unique∃ Forall objects that 1) have an arrow from A and B 2) there exists a unique arrow from S
Compare to programming: traitMonoid[M] { def id: M def compose(a: M, b: M): M } trait Foldable[F[_]] { def foldMap[M: Monoid, A]( fa: F[A], f: A => M): M }
Like UMPs, typeparameters “for all F” “for all A and M where M is a Monoid” don’t just prove what your code is, but what it isn’t.
Proving what yourcode isn’t prevents bloat and error, and promotes reuse. Proving what your code is allows you to use it.
Another way oflooking at it… C A Bfg h If f ∘ g = f ∘ h, then g = h
Injections in code User( firstName= "Bob", lastName = "Smith", age = 73) User JSON { “firstName”: "Bob", “lastName”: ”Smith”, “age”: 73 }
A B C Ifg ∘ f = h ∘ f, then g = h f g h
A B C fg h If g ∘ f = h ∘ f, then g = h
A B C fg h If g ∘ f = h ∘ f, then g = h
It is essentialto understand how information is preserved in flows like this
Isomorphism is more interestingthan equality! Isomorphic types can be rewritten, optimised without error. Isomorphic mappings allow us to preserve information
Further reading Awodey, “CategoryTheory” Lawvere & Schanuel, “Conceptual Mathematics: an introduction to categories” Jeremy Kun, “Math ∩ Programming” at http://jeremykun.com/ Chris Taylor, “The algebra of algebraic datatypes” http://chris-taylor.github.io/blog/2013/02/10/the-algebra-of- algebraic-data-types/ http://chris-taylor.github.io/blog/2013/02/11/the-algebra-of- algebraic-data-types-part-ii/ http://chris-taylor.github.io/blog/2013/02/13/the-algebra-of- algebraic-data-types-part-iii/
Further reading Bartosz Milewski“Categories for Programmers” http://bartoszmilewski.com/2014/10/28/category-theory-for- programmers-the-preface/ http://bartoszmilewski.com/2015/03/13/function-types/