Monad presentation scala as a category


Published on

Published in: Engineering
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Monad presentation scala as a category

  1. 1. Category Theory Theory and Applications for Functional Programming
  2. 2. Format of Talk 1. Introduce definition from Category Theory 2. Use something from Scala as an example 3. Show it satisfies the definition. 4. Do ^^ until Monad defined 5. Prove that definition given in FP is equivalent to definition given in Category Theory Plus random points about application and practicalities along the way
  3. 3. Note about foundations ● Category Theory is itself a foundation of mathematics, and strictly speaking you don’t need Set Theory to do Category Theory ● Nevertheless a lot of examples and language used to explain Category Theory is actually borrowed from Set Theory ● I will do the same as it makes things much easier (strictly speaking I’m using the von Neumann–Bernays–Gödel (NBG) set theory Axiomatization, which is a conservative extension of ZFC that allows us to talk about Proper Classes (e.g. Class of all Sets)
  4. 4. Definition - Category 1. a class ob(C) of objects 2. a class hom(C) of morphisms, or arrows, or maps, between the objects. Each morphism f has a unique source object a and target object b where a and b are in ob(C). We write f: a → b, and we say "f is a morphism from a to b". 3. for every three objects a, b and c, a binary operation hom(a, b) × hom(b, c) → hom(a, c) called composition of morphisms; the composition of f : a → b and g : b → c is written as g ∘ f or gf. (Some authors use "diagrammatic order", writing f;g or fg.) such that the following axioms hold: a. (associativity) if f : a → b, g : b → c and h : c → d then h ∘ (g ∘ f) = (h ∘ g) ∘ f, and b. (identity) for every object x, there exists a morphism 1x : x → x (some authors write idx ) called the identity morphism for x, such that for every morphism f : a → b, we have 1b ∘ f = f = f ∘ 1a .
  5. 5. Example - Scala S Let the set of Types in Scala be Ob(C) Let the set of 1 param Functions in Scala be hom(C) NOTATION: Methods of a Type A, that return a type B that take no params can be equivalently considered as 1 param functions f: A -> B. Therefore I will interchange method invocation and function application henceforth. Composition o is defined as simply normal function composition, now For any f, g, h (types obv) we have (h o (g o f))(x) = (g o f)(h(x)) = f(g(h(x))) = f((h o g)(x)) = ((h o g) o f)(x) - associativity For any T, id_T : T -> T is defined by for any x is a T, id_T(x) = x, clearly this is an identity
  6. 6. Definition - Functor
  7. 7. Example - Parameterized Types Many parameterized types in Scala can be viewed as Functors with their map operation; Let S be the Scala Category, and F: S -> S associate any T in Ob(S) to List[T] in Ob(S) associate any f: A -> B (for any A, B in Ob(S)) to map(f): List[A] -> List[B]. Now for any T in Ob(S) F(id_T)(someList) = => x) = (x => x)(someList) = id_List[T] = id_F[T] - so satisfies identity preservation And it’s obvious that = o f), so satisfies composition preservation Practical Point When you write a parameterized type in an API in Scala with a map function, you are telling the API user that map(f).map(g) is the same as map(f o g). So in Scalding, it’s often convenient to chain map operations together for readability, rather than compose the functions - but Scalding is clever, it will compose the functions for you so that your still O(N) not O(2N), O(3N) etc.
  8. 8. Definition - Natural Transformation .If F and G are functors between the categories C and D, then a natural transformation η from F to G associates to every object X in C a morphism ηX : F(X) → G(X) between objects of D, called the component of η at X, such that for every morphism f : X → Y in C we have:
  9. 9. Example - Flatten Let F: S -> S and G: S -> S be the Option[Option[ _ ]] Functor and Option[ _ ] Functor respectively. NOTATION: will be sloppy henceforth Let f: X -> Y in Hom(S) So F(f): Option[Option[ X ]] -> Option[Option[ Y ] is .map( G(f): Option[X] -> Option[Y] is .map(f)
  10. 10. Example - Flatten - Continued Let N_x be .flatten[x], then flatten is a Natural Transformation: N_Y = flatten[Y]: Option[Option[Y]] -> Option[Y] N_X = flatten[X]: Option[Option[X]] -> Option[X] So N_Y o F(f) = .map( and G(f) o N_X = Now Some(Some(x)).map( = Some(Some(x).map(f)).flatten = Some(Some(f(x)).flatten = Some(f(x)) = Some(x).map(f) = Some(Some(x)) Note there are many more natural transformations, like if we defined toList on Option. Practical Point Knowing an operation is a natural transformation makes refactoring easier.
  11. 11. Definition - Monad!!
  12. 12. Example - Option Monad Let F be the Option Functor, then combined with the flatten natural transformation M we have a monad: For any X in Ob(S) F(M_X) = map(_.flatten) : Option[Option[Option[X]]] -> Option[Option[X]] M_F(X) = M_Option[X] = flatten[Option[X]]: Option[Option[Option[X]]] -> Option[Option[X]] so M_X o F(M_X) = .map(_.flatten).flatten : Option[Option[Option[X]]] -> Option[X] M_X o M_F(X) = .flatten.flatten : Option[Option[Option[X]]] -> Option[X] Let’s check these are equal Some(Some(Some(x))).map(_.flatten).flatten = Some(Some(Some(x)).flatten).flatten = Some(Some(x)).flatten = Some(x) = Some(Some(x)).flatten = Some(Some(Some(x))).flatten.flatten Therefore we have the first coherence condition ...
  13. 13. Example - Option Monad continued Now our Identity natural transformation will be the Some function, i.e. N_X = Some: X -> Option[X] (which is the same as Id(X) -> Option[X]) so F(N_X) = .map(Some), so M_X o F(N_X) = .map(Some).flatten, which is clearly the identity Functor (other way round - exercise)
  14. 14. Definition - Monad in FP In functional programming a monadic Type M is simply defined in terms of flatMap, where: For any f: X -> M[Y], g: Y -> M[Z], and any x: M[X] x.flatMap(f).flatMap(g) = x.flatMap(f(_).flatMap(g)) and there exists a neutral element N: X -> M[X], where x.flatMap(N) = x
  15. 15. Theorem - Equivalence The two previous definitions are equivalent when we make the following substitution .map(f).flatten for flatMap(f) - (*) Proof: .flatten.flatten = .map(_.flatten).flatten - Monad Category Theory => .map(f(_).map(g)).flatten.flatten = .map(f(_).map(g)).map(_.flatten).flatten - by substituting in .map(f(_).map(g)) Now RHS = .map(f(_).map(g).flatten).flatten - by Functor Composition Preservation = .flatMap(f(_).map(g).flatten) - by (*) = .flatMap(f(_).flatMap(g)) - by (*) ...
  16. 16. Proof continued Now LHS = - by Functor Composition Preservation = - since flatten is a natural transformation (recall earlier slide) = x.flatMap(f).flatMap(g) - by (*) twice. Therefore .flatMap(f(_).flatMap(g)) = .flatMap(f).flatMap(g) It remains to show the identity conditions (exercise)
  17. 17. Further Reading Monoids - Used in Reduce operations in Map Reduce to parallelize operations that cumulate a single value. E.g. + is a monoid. Covariance and Contravariance - Used in Typing rules for type inference
  18. 18. Summary of Applications 1. Using Category Theoretic notions in code is a little like a formalization of design patterns 2. When a reader sees a particular notion, they need to use less cognitive resources to comprehend the code by familiarity 3. It’s easier to refactor code due to known equivalences, some of these equivalences are even used by Intellij (and ReSharper for LINQ) for the auto- refactor shortcuts 4. Sometimes APIs allow the user to write readable code, but the resulting compiled code will be in it’s most computationally efficient representation. 5. Compilers use concepts in Category Theory 6. State hiding FP design