Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A practical introduction to Category Theory - Voxxed Days Zurich 2017

A practical introduction to Category Theory - Voxxed Days Zurich 2017

Category Theory has become one of the hot topics in our community. Why is this theory suddenly so interesting for developers? Why are the cool kids talking so much about it? How can we apply its principles in our code? This talk will introduce the general principles behind Category Theory, it will show practical examples of how this theory has managed to simplify and solve common challenges that we encounter in our code daily.

Daniela Sfregola

February 23, 2017
Tweet

More Decks by Daniela Sfregola

Other Decks in Technology

Transcript

  1. A PRACTICAL
    INTRODUCTION TO
    CATEGORY THEORY
    @DANIELASFREGOLA
    VOXXED DAYS ZURICH 2017

    View full-size slide

  2. HELLOOOOO
    > ex Java Developer
    > OOP background
    > I am not a mathematician !

    View full-size slide

  3. HOW DO WE
    REASON ?

    View full-size slide

  4. COMPOSITION
    ABSTRACTION

    View full-size slide

  5. OBJECT ORIENTED PROGRAMMING (OOP)
    > composition of objects
    > abstraction over the behaviour of each object

    View full-size slide

  6. FUNCTIONAL PROGRAMMING (FP)
    > composition of functions
    > abstraction over mathematical laws

    View full-size slide

  7. CATEGORY THEORY

    View full-size slide

  8. CATEGORY THEORY
    ARROW THEORY

    View full-size slide

  9. WHAT IS A CATEGORY?

    View full-size slide

  10. WHAT IS A CATEGORY?

    View full-size slide

  11. MONAD
    TODO LIST PATTERN

    View full-size slide

  12. LET'S BAKE SOME PIZZA!
    1) get the dough
    2) get the sauce
    3) get the cheese
    3) cook in the oven until golden

    View full-size slide

  13. OOP APPROACH
    Ingredient dough = getDough()
    Ingredient sauce = getSauce()
    Ingredient cheese = getCheese()
    def cook(ingredients: List[Ingredient]): Pizza = ???
    if (dough != null && sauce != null && cheese != null)
    cook(dough, sauce, cheese)
    else EXPLODE

    View full-size slide

  14. MONADIC APPROACH
    def getDough(): Option[Ingredient] = ???
    def getSauce(): Option[Ingredient] = ???
    def getCheese(): Option[Ingredient] = ???
    def cook(ingredients: List[Ingredient]): Pizza = ???
    for {
    dough <- getDough()
    sauce <- getSauce()
    cheese <- getCheese()
    } yield cook(dough, sauce, cheese)

    View full-size slide

  15. DIFFERENT TYPES OF MONADS
    > Option
    > Try
    > Future
    > ...
    > ...Yours here!

    View full-size slide

  16. DATA VALIDATION
    > In almost every application
    > Can be come complex quite quickly
    > Needs to be maintained

    View full-size slide

  17. MAP
    scala> Some("daniela").map(s => "yo " + s)
    res0: Option[String] = Some(yo daniela)
    scala> None.map(s => "yo " + s)
    res1: Option[String] = None

    View full-size slide

  18. FLATMAP
    map + flatten
    scala> Some("daniela").flatMap(s => Some("yo " + s))
    res2: Option[String] = Some(yo daniela)
    scala> None.flatMap(s => Some("yo " + s))
    res3: Option[String] = None

    View full-size slide

  19. FOR-COMPREHENSION
    map + flatMap + (filter)
    scala > for { a <- Some(1); b <- Some(5) } yield a + b
    res4: Option[Int] = Some(6)
    scala > for { a <- Some(1); b <- None } yield a + b
    res5: Option[Int] = None

    View full-size slide

  20. OPTION
    package scala
    sealed abstract class Option[A]
    final case class Some[A](x: A) extends Option[A]
    case object None extends Option[Nothing]
    def map[B](f: A => B): Option[B] = ???
    def flatMap[B](f: A => Option[B]): Option[B] = ???

    View full-size slide

  21. OPTION
    case class Data(email: String, phone: String)
    def validateEmail(e: String): Option[String] = ???
    def validatePhone(p: String): Option[String] = ???
    def validateData(d: Data): Option[Data] =
    for {
    validEmail <- validateEmail(d.email)
    validPhone <- validatePhone(d.phone)
    } yield new Data(validEmail, validPhone)

    View full-size slide

  22. OPTION
    val okEmail = "[email protected]"; val badEmail = "email.com"
    val okPhone = "+1 1234567890123"; val badPhone = "not-a-valid-phone"
    > validateData(Data(okEmail, okPhone))
    res0: Option[Data] = Some(Data([email protected],+1 1234567890123))
    > validateData(Data(badEmail, badPhone))
    res1: Option[Data] = None
    > validateData(Data(okEmail, badPhone))
    res2: Option[Data] = None
    > validateData(Data(badEmail, okPhone))
    res3: Option[Data] = None

    View full-size slide

  23. Y U NO TELL ME
    WHICH ONE IS THE WRONG ONE?

    View full-size slide

  24. EITHER
    package scala.util
    sealed abstract class Either[A, B]
    final case class Left[A](a: A) extends Either[A, B]
    final case class Right[B](b: B) extends Either[A, B]
    def map[D](f: B => D): Either[A, D] = ???
    def flatMap[AA >: A, D](f: B => Either[AA, D]): Either[AA, D] = ???

    View full-size slide

  25. EITHER
    case class Data(email: String, phone: String)
    def validateEmail(e: String): Either[List[String], String] = ???
    def validatePhone(p: String): Either[List[String], String] = ???
    def validateData(d: Data): Either[List[String], Data] =
    for {
    validEmail <- validateEmail(d.email)
    validPhone <- validatePhone(d.phone)
    } yield new Data(validEmail, validPhone)

    View full-size slide

  26. EITHER
    val okEmail = "[email protected]"; val badEmail = "email.com"
    val okPhone = "+1 1234567890123"; val badPhone = "not-a-valid-phone"
    > validateData(Data(okEmail, okPhone))
    res0: Either[List[String],Data] = Right(Data([email protected],+1 1234567890123))
    > validateData(Data(badEmail, badPhone))
    res1: Either[List[String],Data] = Left(List("Invalid email format"))
    > validateData(Data(okEmail, badPhone))
    res2: Either[List[String],Data] = Left(List("Phone number must be numeric"))
    > validateData(Data(badEmail, okPhone))
    res3: Either[List[String],Data] = Left(List("Invalid email format"))

    View full-size slide

  27. EITHER
    > only one validation is performed
    > ideal only when error accumulation
    is not needed

    View full-size slide

  28. EITHER
    case class Data(email: String, phone: String)
    def validateEmail(e: String): Either[List[String], String] = ???
    def validatePhone(p: String): Either[List[String], String] = ???
    def validateData(d: Data): Either[List[String], Data] = {
    val validEmail = validateEmail(d.email)
    val validPhone = validatePhone(d.phone)
    (validEmail, validPhone) match {
    case (Right(e), Right(p)) => Right(new Data(e, p))
    case (Left(errE), Left(errP)) => Left(errE ++ errP)
    case (Left(errE), _) => Left(errE)
    case (_, Left(errP)) => Left(errP)
    }
    }

    View full-size slide

  29. EITHER
    val okEmail = "[email protected]"; val badEmail = "email.com"
    val okPhone = "+1 1234567890123"; val badPhone = "not-a-valid-phone"
    > validateData(Data(okEmail, okPhone))
    res0: Either[List[String],Data] = Right(Data([email protected],+1 1234567890123))
    > validateData(Data(badEmail, badPhone))
    res1: Either[List[String],Data] =
    Left(List("Invalid email format", "Phone number must be numeric"))
    > validateData(Data(okEmail, badPhone))
    res2: Either[List[String],Data] = Left(List("Phone number must be numeric"))
    > validateData(Data(badEmail, okPhone))
    res3: Either[List[String],Data] = Left(List("Invalid email format"))

    View full-size slide

  30. EITHER
    Which one is the error?
    Which one is the valid value?
    Combine Either instances
    is not always
    easy or maintainable

    View full-size slide

  31. APPLICATIVE FUNCTOR

    View full-size slide

  32. VALIDATED
    package cats.data
    sealed abstract class Validated[+E, +A]
    final case class Valid[+A](a: A) extends Validated[Nothing, A]
    final case class Invalid[+E](e: E) extends Validated[E, Nothing]
    def map[B](f: A => B): Validated[E,B]
    // no flatmap
    //...but we have something else *really* useful!

    View full-size slide

  33. VALIDATED AND APPLY*
    import cats.Apply
    import cats.data.Validated
    import cats.implicits._
    def accumulate[E, A1, A2, B](v1: Validated[E, A1],
    v2: Validated[E, A2])
    (f: (A1, A2) => B): Validated[E, B] =
    (v1 |@| v2).map(f)
    // same as: Apply[Validated[E, ?]].map2(v1,v2)(f)
    * More info on Apply at http://typelevel.org/cats/typeclasses/apply.html

    View full-size slide

  34. VALIDATED
    import cats.implicits._
    import cats.data.Validated
    case class Data(email: String, phone: String)
    def validateEmail(e: String): Validated[List[String], String] = ???
    def validatePhone(p: String): Validated[List[String], String] = ???
    def validateData(d: Data): Validated[List[String], Data] = {
    val validEmail = validateEmail(d.email)
    val validPhone = validatePhone(d.phone)
    (validEmail |@| validPhone).map(Data)
    }

    View full-size slide

  35. VALIDATED
    val okEmail = "[email protected]"; val badEmail = "email.com"
    val okPhone = "+1 1234567890123"; val badPhone = "not-a-valid-phone"
    > validateData(Data(okEmail, okPhone))
    res0: cats.data.Validated[List[String],Data] = Valid(Data([email protected],+1 1234567890123))
    > validateData(Data(badEmail, badPhone))
    res1: cats.data.Validated[List[String],Data] =
    Invalid(List("Invalid email format", "Phone number must be numeric"))
    > validateData(Data(okEmail, badPhone))
    res2: cats.data.Validated[List[String],Data] = Invalid(List("Phone number must be numeric"))
    > validateData(Data(badEmail, okPhone))
    res3: cats.data.Validated[List[String],Data] = Invalid(List("Invalid email format"))

    View full-size slide

  36. SUMMARY
    > Category Theory: how things compose
    > Monads: good for concatenation
    > Applicative Functors: good for validation

    View full-size slide

  37. FORGET ABOUT THE DETAILS
    FOCUS ON
    HOW THINGS COMPOSE

    View full-size slide

  38. WANNA KNOW MORE?
    > Video: Category Theory for the Working Hacker by
    @PhilipWadler
    > Video: Category Theory by @BartoszMilewski

    View full-size slide

  39. THANK YOU!
    > Code on github:
    github.com/DanielaSfregola/data-validation
    > Twitter: @DanielaSfregola
    > Blog: danielasfregola.com

    View full-size slide