It's All About Morphisms
Total Page:16
File Type:pdf, Size:1020Kb
It’s All About Morphisms Uberto Barbini @ramtop https://medium.com/@ramtop About me OOP programmer Agile TDD Functional PRogramming Finance Kotlin Industry Blog: https://medium.com/@ ramtop Twitter: @ramtop #morphisms#VoxxedVienna @ramtop Map of this presentation Monoid Category Monad Functor Natural Transformation Yoneda Applicative Morphisms all the way down... #morphisms#VoxxedVienna @ramtop I don’t care about Monads, why should I? Neither do I what I care about is y el is to define system behaviour ec Pr #morphisms#VoxxedVienna @ramtop This presentation will be a success if most of you will not fall asleep #morphisms#VoxxedVienna @ramtop This presentation will be a success if You will consider that Functional Programming is about transformations and preserving properties. Not (only) lambdas and flatmap #morphisms#VoxxedVienna @ramtop What is this Category thingy? Invented in 1940s “with the goal of understanding the processes that preserve mathematical structure.” “Category Theory is about relation between things” “General abstract nonsense” #morphisms#VoxxedVienna @ramtop Once upon a time there was a Category of Stuffed Toys and a Category of Tigers... #morphisms#VoxxedVienna @ramtop A Category is defined in 5 steps: 1) A collection of Objects #morphisms#VoxxedVienna @ramtop A Category is defined in 5 steps: 2) A collection of Arrows #morphisms#VoxxedVienna @ramtop A Category is defined in 5 steps: 3) Each Arrow works on 2 Objects #morphisms#VoxxedVienna @ramtop A Category is defined in 5 steps: 4) Arrows can be combined #morphisms#VoxxedVienna @ramtop A Category is defined in 5 steps: 5) Each Object has an Identity (an arrow pointing to itself) #morphisms#VoxxedVienna @ramtop #morphisms#VoxxedVienna @ramtop A Category Example Tube Map: Objects → stations stations Arrows → stations travel routes Each Arrows connect 2 stations Arrow composition is travelling along the line Identity Arrow is staying in the same station #morphisms#VoxxedVienna @ramtop London Tube Category #morphisms#VoxxedVienna @ramtop Monoid Category Monad Functor Natural Transformation Yoneda Applicative This presentation is a Category as well! #morphisms#VoxxedVienna @ramtop AddItem Ready NewOrder Dispatch Dispatched Cancel Close Return Cancelled Closed Returned Event Source Category https://skillsmatter.com/skillscasts/11486-functional-cqrs #morphisms#VoxxedVienna @ramtop Functional Programming is also a Category Each programming language has a Category: Types are the objects and Functions are the morphisms. Partial functions don’t have a defined return for all inputs. In reality all programming functions are partial: they can raise Exceptions or never end. They always have an hidden return of Bottom Type (⊥)) #morphisms#VoxxedVienna @ramtop Change of mindset! Object Oriented Functional Living Bacteria Gears and Pipes Opaque Transparent Hidden State Immutable State Interfaces Type Classes #morphisms#VoxxedVienna @ramtop Kotlin for functional programming ● Nullable and not-nullable types ● Type Aliases ● Class extensions ● Tail recursion ● Pattern matching (when) ● Arrow-kt bindinds with coroutines ● Arrow-kt Typeclasses (?) #morphisms#VoxxedVienna @ramtop arrow-kt.io #morphisms#VoxxedVienna @ramtop KEEP-87 TypeClasses #morphisms#VoxxedVienna @ramtop Purity and Immutability For the Category morphisms to work in programming we need Purity and Immutability. But they are not a goal per se, only a necessity for the main goal: composition and transformation. Ultimately everything is converted in assembly which is neither pure nor immutable. We need those quality only for exposed code #morphisms#VoxxedVienna @ramtop Monoid What about the category of morphisms of a category? Are they composable? It’s a Category with a single Object and lots of Morphisms A Category with only one Object is a Monoid #morphisms#VoxxedVienna @ramtop #morphisms#VoxxedVienna @ramtop Programming with Monoids A type class with two methods combine → stations monoid append empty → stations neutral element (x <> y) <> z = x <> (y <> z) -- associativity empty <> x = x -- left identity x <> empty = x -- right identity #morphisms#VoxxedVienna @ramtop Generics Type Contructors List<A> is just an abstract type to build List<Int> List<String> List<User> etc. #morphisms#VoxxedVienna @ramtop Type Class vs Interface ● Interfaces “unify” different types: Cat and Dogs can be treated as Animals ● Type Classes “group” types with similar behaviour, without hiding their types: Cats and Dogs can both form couples but cats can mate only with cats and dogs with dogs. You cannot represent that with interfaces. #morphisms#VoxxedVienna @ramtop Typeclass Instances ● Typeclasses work with instances (like a singleton) ● List is not a Monoid nor a Functor nor a Monad but it has an (or more) instance of Monoid one of Functor and one of Monad ● Technically we implement instances as an interface with a singletons specific implementation. ● We can have different implementation for difference in evaluation, for example because of concurrency #morphisms#VoxxedVienna @ramtop Enough talk, let’s see the code! Monoid TypeClass Instances... ...Give us the combine extension function #morphisms#VoxxedVienna @ramtop The future (?) extension interface Monoid<T> { infix fun T.add(t: T): T } extension object IntMonoid: Monoid<Int> { inline fun Int.add(t: Int) = this + t } inline fun <T> sum(t1: T, t2: T, t3: T, with Monoid<T>) = t1 add t2 add t3 fun main() { sum(1, 2, 3) //no boxing because of inlining } #morphisms#VoxxedVienna @ramtop Transformers a.k.a. Functors #morphisms#VoxxedVienna#morphisms Very Important!! @ramtop Functors Functors can map both objects (types) and morphism (functions) between two categories Functors map must preserve the structure and some properties But can also work inside the same category (Endofunctors) #morphisms#VoxxedVienna @ramtop Functor Laws Functor is a TypeClass with a Map function that works like this. Id is the identity function. map id x = x map (g <> f) = map g <> map f) Passing the ID function must return the original value Map must honour associativity of two functions #morphisms#VoxxedVienna @ramtop #morphisms#VoxxedVienna @ramtop Try Functor Keep a context and Map operation on `it Failure without Exception #morphisms#VoxxedVienna @ramtop Functors are also Forklifts Lift a function from A --> B to F<A> --> F<B> val lifted = Try.functor().lift {x:String -> x.toInt()} lifted(Try.Success("42")) //Try.Success(42) #morphisms#VoxxedVienna @ramtop Yoneda Lemma Yoneda's lemma concerns functors from a fixed category C to the category of sets, Set. If C is a locally small category (i.e. the hom- sets are actual sets and not proper classes), then each object A of C gives rise to a natural functor to Set called a hom-functor. #morphisms#VoxxedVienna @ramtop Yoneda Lemma F<?>.map(A→B): F<B> (? must be A) The actual implementation is useful to compose of mappings without executing until we decide combine all the maps in one and then apply it. No copies of List #morphisms#VoxxedVienna @ramtop Natural Transformations A natural transformation provides a way of transforming one functor into another while respecting the internal structure of the categories involved. Transforming Data → Functions Transforming Functions → Functors Transforming Functors → Natural Transformations #morphisms#VoxxedVienna @ramtop Natural Transformations #morphisms#VoxxedVienna @ramtop Natural Transformations val list = Try {"3".toInt()}.toOption().toList() //[3] val fail = Try {"xyz".toInt()}.toOption().toList() //[] #morphisms#VoxxedVienna @ramtop Combining Functors We can imagine 2 ways to combine 2 functors F + F = F F<f> map F<a> = F<f(a)> or F * F = F flatmap (a → F<a → F<a>>) = F a #morphisms#VoxxedVienna @ramtop Applicative Functors ● We can combine a value inside a Functor with a function inside another Functor ● If the function want more than 1 param, it will return a function with x-1 params. ● Applicative can apply: ● F<A> applied to F<A->B> to create F<B> #morphisms#VoxxedVienna @ramtop Try Applicative Functor Silly example of function that can raise an Exception Exception raised! #morphisms#VoxxedVienna @ramtop The M word... ● What about a category of (endo)functors? ● Some functors have a monoid instance, others not. ● How can we call the Category of Endofunctors with a Monoid instance? A Monad is just a Monoid in the category of Endofunctors, what's the problem? #morphisms#VoxxedVienna @ramtop Monad Recipe #morphisms#VoxxedVienna @ramtop Monads Allow Sequences of Instructions #morphisms#VoxxedVienna @ramtop Monads Binding From here: val university: IO<University> = getStudent("John Smith").flatMap { student -> getUniversity(student.universityId).flatMap { university -> getDean(university.deanId) } } To here: val university: IO<University> = IO.monad().binding { val student = getStudent("John Smith").bind() val university = getUniversity(student.universityId).bind() val dean = getDean(university.deanId).bind() dean } #morphisms#VoxxedVienna @ramtop Functional Programming Dilemma: Perfectly Pure Programs are Perfectly Useless Enter Ef fects #morphisms#VoxxedVienna @ramtop Dependency Injection courtesy of Reader Monad fun getUser(userId:String):Reader<Context, User> { fun getCommonFriends(u1: User, u2: User): Reader<Context, List<User>> What’s happen if user cannot be fetched? Runs here #morphisms#VoxxedVienna @ramtop Monads Zoo ● Option All Monads are also Functors and ● Try Applicative, but the opposite is not true. ● List Each Monad as it’s specific logic on top ● Either of the Monads Laws ● Reader These