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

Concrete Abstraction with Scalaz • Scala Leipzig 2015

Martin Kühl
February 26, 2015
79

Concrete Abstraction with Scalaz • Scala Leipzig 2015

Introducing some of the core Abstractions from Scalaz and practical use cases:
• Monoids
• Monads
• Applicative Functors

Martin Kühl

February 26, 2015
Tweet

Transcript

  1. Compare: Design Patterns • provide common vocabulary • recognize that

    they were used • recognize when they could be used 4
  2. Have: Map("a" -> List(1), "b" -> List(2, 2), "c" ->

    List(3, 4, 5)) Want: Map("a" -> Agree(1), "b" -> Agree(2), "c" -> Disagree(3, 4, 5)) 9
  3. trait Consensus[A] case object Unknown extends Consensus[Nothing] case class Agree[A](get:

    A) extends Consensus[A] case class Disagree[A](all: Set[A]) extends Consensus[A] 10
  4. Have: Map("a" -> List(1), "b" -> List(2, 2), "c" ->

    List(3, 4, 5)) Want: Map("a" -> Agree(1), "b" -> Agree(2), "c" -> Disagree(3, 4, 5)) 11
  5. def aggregate[A](c: Consensus[A], a: A): Consensus[A] = c match {

    case Unknown => Agree(a) case Disagree(as) => Disagree(as + a) case Agree(b) => if (a == b) c else Disagree(Set(b, a)) } 12
  6. 14

  7. scala> List(2, 3, 4) foldMap (x=>x) res2: Int = 9

    scala> List[Int]() foldMap (x=>x) res3: Int = 0 19
  8. scala> List(2, 3, 4).toSet res8: Set[Int] = Set(2, 3, 4)

    scala> List[Int]().toSet res9: Set[Int] = Set() 20
  9. scala> List(2, 3, 4) foldMap (Set(_)) res10: Set[Int] = Set(2,

    3, 4) scala> List[Int]() foldMap (Set(_)) res11: Set[Int] = Set() 21
  10. trait Consensus[A] case object Unknown extends Consensus[Nothing] case class Agree[A](get:

    A) extends Consensus[A] case class Disagree[A](all: Set[A]) extends Consensus[A] 22
  11. scala> Map("a" -> List(1), | "b" -> List(2, 2), |

    "c" -> List(3, 4, 5)) | mapValues (_ foldMap (agree(_))) res13: Map[String,Consensus[Int]] = Map(a -> Agree(1), b -> Agree(2), c -> Disagree(Set(3, 4, 5))) 23
  12. scala> val l: Map[String, Consensus[Int]] = | Map("a" -> Agree(1),

    "b" -> Agree(2), | "c" -> Disagree(Set(3, 4))) scala> val r: Map[String, Consensus[Int]] = | Map("a" -> Agree(1), "b" -> Agree(1), | "c" -> Disagree(Set(4, 5))) scala> l mappend r res17: Map[String,Consensus[Int]] = Map(a -> Agree(1), b -> Disagree(Set(1, 2)), c -> Disagree(Set(3, 4, 5))) 24
  13. trait TwitterService[F[_]] { def text(id: Long): F[String] def retweets(id: Long):

    F[Long] def favourites(id: Long): F[Long] } case class Tweet( text: String, retweets: Long, favourites: Long) 35
  14. trait Applicative[F[_]] extends Functor[F] { def pure[A](a: => A): F[A]

    def ap[A, B](fa: F[A])(f: F[A => B]): F[B] // ... } 36
  15. scala> (text(id) |@| retweets(id) |@| favourites(id)) | { Tweet }

    res0: Option[Tweet] = Some(Tweet(BONG BONG BONG BONG,98,48)) 45
  16. scala> (text(id) |@| retweets(id) |@| favourites(id)) | { Tweet }

    res1: Future[Tweet] = Promise$DefaultPromise@4b4257a5 scala> res1 foreach println Tweet(BONG BONG BONG BONG,98,48) 46
  17. scala> retweets(id) res2: (List[String], Long) = (List(fetching retweets…),98) scala> (text(id)

    |@| retweets(id) |@| favourites(id)) | { Tweet } res3: (List[String], Tweet) = (List(fetching text…, fetching retweets…, fetching favourites…), Tweet(BONG BONG BONG BONG,98,48)) 47
  18. trait ProfileService[F[_]] { def author(id: Long): F[String] def name(screenname: String):

    F[String] def url(screenname: String): F[String] } case class Profile( screenname: String, name: String, url: String) 49
  19. trait Monad[F[_]] extends Applicative[F] { def point[A](a: => A): F[A]

    def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] // ... } 50
  20. scala> for { | screenname <- author(id) | name <-

    name(screenname) | url <- url(screenname) | } yield Profile(screenname, name, url) res0: Option[Profile] = Some(Profile(big_ben_clock, Big Ben, twitter.com/big_ben_clock)) 58
  21. scala> for { | screenname <- author(id) | name <-

    name(screenname) | url <- url(screenname) | } yield Profile(screenname, name, url) res1: Future[Profile] = Promise$DefaultPromise@6329614f scala> res1 foreach println Profile(big_ben_clock, Big Ben, twitter.com/big_ben_clock)) 59
  22. scala> for { | screenname <- author(id) | (name, url)

    <- | (name(screenname) |@| url(screenname)) {(_,_)} | } yield Profile(screenname, name, url) res2: Future[Profile] = Promise$DefaultPromise@1feca79a scala> res2 foreach println Profile(big_ben_clock, Big Ben, twitter.com/big_ben_clock)) 60
  23. scala> for { | screenname <- author(id) | name <-

    name(screenname) | url <- url(screenname) | } yield Profile(screenname, name, url) res2: WriterT[Id.Id,List[String],Profile] = WriterT((List(fetching author…, fetching name…, fetching URL…), Profile(big_ben_clock, Big Ben, twitter.com/big_ben_clock))) 61
  24. Summary Monoids aggregate data (possibly in parallel) Applicative Functors combine

    independent computations Monads combine (possibly dependent) computations 69
  25. Summary • These abstractions provide practical value • Scalaz provides

    high-quality implementation • Learn more about them • Try using them on your problems 70
  26. Further Reading • Functional Programming in Scala • Typeclassopedia •

    Learning Scalaz • Typeclass 101 • Life After Monoids • Realtime MapReduce at Twitter • Eventually consistent computation with CRDTs • Comonads, Applicative Functors, Monads and Other Principled Things • Of Algebirds, Monoids, Monads, and Other Bestiary for Large-Scale Data Analytics • Functors, Applicatives, And Monads In Pictures • Abstraction, intuition, and the “monad tutorial fallacy” • Monads Are Not Metaphors • Scalaz Resources for Beginners • Rúnar Bjarnason • Paul Chiusano • Typelevel • Underscore 71