Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
TRAVERSALS FOR ALL
OCCASIONS
Luka Jacobowitz
Software Developer at codecentric
Co-organizer of ScalaDus and
IdrisDus
Maintainer of cats, cats-effect,
cats-mtl, OutWatc...
Motivation
● Traversable is my favorite type class
● Not enough people know about it
● Even less people know about some of...
Motivation
Teaser
How do you create a List of Http Requests run them all in parallel and if errors
occur accumulate them?
userIdList....
Traverse
[T[_]: Traverse, F[_]: Applicative, A]: T[F[A]] => F[T[A]]
E.g.
List[Future[A]] => Future[List[A]]
Vector[Option[...
Traverse
[T[_]: Traverse, F[_]: Applicative, A]: T[F[A]] => F[T[A]]
Traverse runs an action(F[_]) for every element in a d...
Traverse
trait Applicative[F[_]] {
def map2[A, B, C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C]
def pure[A](a: A): F[A]
}
A...
Traverse
trait Traverse[T[_]] {
def sequence[F[_]: Applicative, A](tfa: T[F[A]]): F[T[A]]
def traverse[F[_]: Applicative, ...
Traverse
List[Future[A]] => Future[List[A]]
Vector[Option[A]] => Option[Vector[A]]
Either[E, IO[A]] => IO[Either[E, A]]
ty...
FoldMap
trait Foldable[T[_]] {
def foldMap[A, M: Monoid](ta: T[A], f: A => M): M
def fold[M: Monoid](ta: T[M]): M
}
t.fold...
NonEmpty
trait Reducible[T[_]] {
def reduceMap[A, S: Semigroup](ta: T[A], f: A => S): S
def reduce[S: Semigroup](ta: T[S])...
NonEmpty
def maximum[A: Order](nel: NonEmptyList[A]): A =
reduceMap(nel)(Max)
def minimum[A: Order](nel: NonEmptyList[A]):...
NonEmpty
def countWords(text: String): Map[String, Int] =
words.split(" ").groupBy(identity).mapValues(_.length)
val lines...
Commutativity
trait UnorderedFoldable[T[_]] {
def unorderedFold[M: CommutativeMonoid](ta: T[M]): M
}
trait UnorderedTraver...
Commutativity
CommutativeMonoid:
a |+| b <-> b |+| a
E.g: Int, Set[String]
Commutativity
val users: HashSet[User]
val result =
users.unorderedFoldMap(_.billableHours)
Commutativity
CommutativeApplicative:
map2(fa, fb)((a, b) => f(a, b)) <-> map2(fb, fa)((b, a) => f(a, b))
fa *> fb <-> fb ...
Commutativity
type ValidatedNes[E, A] = Validated[NonEmptySet[E], A]
val result: ValidatedNes[Error, RDD[User]] =
users.un...
FlatTraverse
trait Traverse[T[_]] {
def flatTraverse[G[_]: Applicative, A, B](ta: T[A])
(f: A => G[T[B]])(implicit T: Flat...
FlatTraverse
val maybeUser: Option[User]
def fetchAddress(user: User): IO[Option[Address]]
val result: IO[Option[Address]]...
Parallelism
trait Parallel[M[_]: Monad, F[_]: Applicative] {
def parallel: FunctionK[M, F]
def sequential: FunctionK[F, M]...
Revisiting the teaser
def request(userId: Int): EitherT[IO, Nel[Error], User]
val result: IO[EitherNel[Error, List[User]]]...
Other traversals
traverseWithIndex
unorderedFlatTraverse
traverseWithIndexM
traverse_
parFlatTraverse
nonEmptyFlatTraverse...
Other traversals
traverseWithIndex
unorderedFlatTraverse
traverseWithIndexM
traverse_
parFlatTraverse
nonEmptyFlatTraverse...
Useful stuff!
def parNonEmptyUnorderedSequence
[T[_]: NonEmptyUnorderedTraverse, M[_], F[_], A](ta: T[M[A]])
(implicit P: ...
Useful stuff!
def groupByNem[A, K](nel: NonEmptyList[A])
(f: A => K): NonEmptyHashMap[K, NonEmptyList[A]]
users.groupByNem...
Summary
Traverse is a great abstraction, because it allows us to traverse data structures
using Applicative Functors, whic...
Thank you all for
listening!
Twitter:
@LukaJacobowitz
GitHub:
LukaJCB
You’ve finished this document.
Download and read it offline.
Upcoming SlideShare
What to Upload to SlideShare
Next
Upcoming SlideShare
What to Upload to SlideShare
Next
Download to read offline and view in fullscreen.

Share

Traversals for all ocasions

Download to read offline

Scalar 2018

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Traversals for all ocasions

  1. 1. TRAVERSALS FOR ALL OCCASIONS Luka Jacobowitz
  2. 2. Software Developer at codecentric Co-organizer of ScalaDus and IdrisDus Maintainer of cats, cats-effect, cats-mtl, OutWatch Enthusiastic about FP About me
  3. 3. Motivation ● Traversable is my favorite type class ● Not enough people know about it ● Even less people know about some of the less common traversals out there ● Have some fun while learning!
  4. 4. Motivation
  5. 5. Teaser How do you create a List of Http Requests run them all in parallel and if errors occur accumulate them? userIdList.parTraverse(request).value
  6. 6. Traverse [T[_]: Traverse, F[_]: Applicative, A]: T[F[A]] => F[T[A]] E.g. List[Future[A]] => Future[List[A]] Vector[Option[A]] => Option[Vector[A]]
  7. 7. Traverse [T[_]: Traverse, F[_]: Applicative, A]: T[F[A]] => F[T[A]] Traverse runs an action(F[_]) for every element in a data structure (T[_]), and accumulates the results.
  8. 8. Traverse trait Applicative[F[_]] { def map2[A, B, C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] def pure[A](a: A): F[A] } Applicatives allow us to combine two or more independent values inside a context.
  9. 9. Traverse trait Traverse[T[_]] { def sequence[F[_]: Applicative, A](tfa: T[F[A]]): F[T[A]] def traverse[F[_]: Applicative, A, B](ta: T[A], f: A => F[B]): F[T[B]] } t.traverse(f) <-> t.map(f).sequence
  10. 10. Traverse List[Future[A]] => Future[List[A]] Vector[Option[A]] => Option[Vector[A]] Either[E, IO[A]] => IO[Either[E, A]] type EitherE[A] = Either[E, A] List[Validated[E, A]] => Validated[E, List[A]]
  11. 11. FoldMap trait Foldable[T[_]] { def foldMap[A, M: Monoid](ta: T[A], f: A => M): M def fold[M: Monoid](ta: T[M]): M } t.foldMap(f) <-> t.map(f).fold def foldMap[A, M: Monoid](ta: T[A], f: A => M): M = ta.traverse(a => Const(f(a))).getConst
  12. 12. NonEmpty trait Reducible[T[_]] { def reduceMap[A, S: Semigroup](ta: T[A], f: A => S): S def reduce[S: Semigroup](ta: T[S]): S } trait NonEmptyTraverse[T[_]] { def nonEmptyTraverse[F[_]: Apply](ta: T[A], f: A => F[B]): F[T[B]] def nonEmptySequence[F[_]: Apply](ta: T[F[A]]): F[T[A]] } t.reduceMap(f) <-> t.map(f).reduce t.nonEmptyTraverse(f) <-> t.map(f).nonEmptySequence
  13. 13. NonEmpty def maximum[A: Order](nel: NonEmptyList[A]): A = reduceMap(nel)(Max) def minimum[A: Order](nel: NonEmptyList[A]): A = reduceMap(nel)(Min)
  14. 14. NonEmpty def countWords(text: String): Map[String, Int] = words.split(" ").groupBy(identity).mapValues(_.length) val lines: NonEmptyList[String] val result: Map[String, NonEmptyList[Int]] = lines.nonEmptyTraverse(countWords)
  15. 15. Commutativity trait UnorderedFoldable[T[_]] { def unorderedFold[M: CommutativeMonoid](ta: T[M]): M } trait UnorderedTraverse[T[_]] { def unorderedSequence[F[_]: CommutativeApplicative, A] (ta: T[F[A]]): F[T[A]] }
  16. 16. Commutativity CommutativeMonoid: a |+| b <-> b |+| a E.g: Int, Set[String]
  17. 17. Commutativity val users: HashSet[User] val result = users.unorderedFoldMap(_.billableHours)
  18. 18. Commutativity CommutativeApplicative: map2(fa, fb)((a, b) => f(a, b)) <-> map2(fb, fa)((b, a) => f(a, b)) fa *> fb <-> fb <* fa E.g. Option, ValidatedNes
  19. 19. Commutativity type ValidatedNes[E, A] = Validated[NonEmptySet[E], A] val result: ValidatedNes[Error, RDD[User]] = users.unorderedTraverse(validate)
  20. 20. FlatTraverse trait Traverse[T[_]] { def flatTraverse[G[_]: Applicative, A, B](ta: T[A]) (f: A => G[T[B]])(implicit T: FlatMap[T]): G[T[B]] } ta.traverse(f).map(_.flatten) <-> ta.flatTraverse(f)
  21. 21. FlatTraverse val maybeUser: Option[User] def fetchAddress(user: User): IO[Option[Address]] val result: IO[Option[Address]] = maybeUser.flatTraverse(fetchAddress)
  22. 22. Parallelism trait Parallel[M[_]: Monad, F[_]: Applicative] { def parallel: FunctionK[M, F] def sequential: FunctionK[F, M] } def parSequence[T[_], M[_], F[_], A](ta: T[M[A]]) (implicit P: Parallel[M, F], T: Traverse[T]): M[T[A]]
  23. 23. Revisiting the teaser def request(userId: Int): EitherT[IO, Nel[Error], User] val result: IO[EitherNel[Error, List[User]]] = userIdList.parTraverse(request).value EitherT[IO, E, A] ⇔ Nested[ParIO, Validated[E, ?], A] IO[Either[E, A]] ⇔ ParIO[Validated[E, A]]
  24. 24. Other traversals traverseWithIndex unorderedFlatTraverse traverseWithIndexM traverse_ parFlatTraverse nonEmptyFlatTraverse parNonEmptyFlatTraverse parNonEmptyUnorderedTraverse
  25. 25. Other traversals traverseWithIndex unorderedFlatTraverse traverseWithIndexM traverse_ parFlatTraverse nonEmptyFlatTraverse parNonEmptyFlatTraverse parNonEmptyUnorderedTraverse + Sequence versions + Almost every other conceivable combination
  26. 26. Useful stuff! def parNonEmptyUnorderedSequence [T[_]: NonEmptyUnorderedTraverse, M[_], F[_], A](ta: T[M[A]]) (implicit P: NonEmptyCommutativeParallel[M, F]): M[T[A]] What could possibly be an instance for this??? NonEmptyUnorderedTraverse: NonEmptyRDD, NonEmptyHashMap NonEmptyCommutativeParallel: NonEmptyList ⇔ NonEmptyZipList
  27. 27. Useful stuff! def groupByNem[A, K](nel: NonEmptyList[A]) (f: A => K): NonEmptyHashMap[K, NonEmptyList[A]] users.groupByNem(_.address) .parNonEmptyUnorderedSequence
  28. 28. Summary Traverse is a great abstraction, because it allows us to traverse data structures using Applicative Functors, which represent independent computations. These traversals capture the essence of imperative loops over these data structures. We can add or remove constraints to the action(F[_]) or the structure types(T[_]) to get slightly different traversals.
  29. 29. Thank you all for listening! Twitter: @LukaJacobowitz GitHub: LukaJCB
  • mcaca441

    Feb. 1, 2021
  • pjschwarz

    Jun. 5, 2020
  • PhilDerome

    Apr. 6, 2018

Scalar 2018

Views

Total views

1,808

On Slideshare

0

From embeds

0

Number of embeds

256

Actions

Downloads

16

Shares

0

Comments

0

Likes

3

×