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

Concrete Abstraction with Scalaz • Scala Exchan...

Martin Kühl
December 08, 2014

Concrete Abstraction with Scalaz • Scala Exchange 2014

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

Martin Kühl

December 08, 2014
Tweet

More Decks by Martin Kühl

Other Decks in Technology

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. 12

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

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

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

    3, 4) scala> List[Int]() foldMap (Set(_)) res11: Set[Int] = Set() 19
  8. 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] 20
  9. 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))) 21
  10. 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))) 22
  11. 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) 30
  12. 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] // ... } 31
  13. scala> (text(id) |@| retweets(id) |@| favourites(id)) | { Tweet }

    res0: Option[Tweet] = Some(Tweet(BONG BONG BONG BONG,98,48)) 36
  14. 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) 37
  15. 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)) 38
  16. 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) 40
  17. 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] // ... } 41
  18. 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)) 46
  19. 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)) 47
  20. 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)) 48
  21. 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))) 49
  22. Summary Monoids aggregate data (possibly in parallel) Applicative Functors combine

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

    high-quality implementation • Learn more about them • Try using them on your problems 52
  24. 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 53