SlideShare uma empresa Scribd logo
1 de 46
Baixar para ler offline
Oh, All the things you’ll traverse
ScalaDays - Luka Jacobowitz
Software Developer at
codecentric
Co-organizer of ScalaDus
and IdrisDus
Maintainer of cats,
cats-effect, cats-mtl,
OutWatch
Enthusiastic about FP
About me
● Type classes
● Monoids
● Functors
● Traversals
Agenda
Type classes ● Type classes offer us
ad-hoc polymorphism
● Operate on types rather
than instances
● Pretty similar to OOP
interfaces (traits)
● No explicit language
support in Scala... (yet)
A small type class example
@typeclass
trait Show[T] {
def show(value: T): String
}
implicit val showString: Show[String] = new Show[String] {
def show(value: String): String = value
}
implicit val showInt: Show[Int] = _.toString
def emptyIfFalse[T: Show](t: T, f: T => Boolean): String =
if (f(t)) t.show else “”
Something a bit more useful
@typeclass
trait Monoid[T] {
def empty: T
def combine(a: T, b: T): T
}
implicit val monoidInt: Monoid[Int] = new Monoid[Int] {
def empty: Int = 0
def combine(a: Int, b: Int): Int = a + b
}
Something a bit more useful
def sumInt(list: List[Int]): Int =
list.foldLeft(0)(_ + _)
def sumString(list: List[String]): String =
list.foldLeft("")(_ + _)
def sumSet[T](list: List[Set[T]]): Set[T] =
list.foldLeft(Set.empty[T])(_ union _)
def sum[T: Monoid](list: List[T]): T =
list.foldLeft(Monoid[T].empty)(_ combine _)
Something a bit more useful
def sumInt(list: List[Int]): Int =
list.foldLeft(0)(_ + _)
def sumString(list: List[String]): String =
list.foldLeft("")(_ + _)
def sumSet[T](list: List[Set[T]]): Set[T] =
list.foldLeft(Set.empty[T])(_ union _)
def sum[T: Monoid](list: List[T]): T =
list.foldLeft(Monoid[T].empty)(_ combine _)
Implicit derivation
implicit def optionMonoid[T: Monoid] = new Monoid[Option[T]] {
def empty = None
def combine(a: Option[T], b: Option[T]) = (a, b) match {
case (Some(x), Some(y)) => Some(x |+| y)
case (Some(x), None) => Some(x)
case (None, Some(y)) => Some(y)
case (None, None) => None
}
}
Type classes vs subtyping
● Type classes give us operations on types instead of on values
● This comes in handy when dealing with type classes like Monoids
● We can use type classes to derive instances for data types that
might hold other data types when they also have instances.
Monoids everywhere
implicit def functionMonoid[A, B: Monoid] = new Monoid[A => B] {
def empty = _ => Monoid[B].empty
def combine(x: A => B, y: A => B): A => B =
a => x(a) |+| y(a)
}
implicit def tupleMonoid[A: Monoid, B: Monoid] = new Monoid[(A, B)] {
def empty = (Monoid[A].empty, Monoid[B].empty)
def combine(x: (A, B), y: (A, B)): (A, B) =
(x._1 |+| y._1, x._2 |+| y._2)
}
Monoids everywhere
implicit def eitherMonoid[A, B: Monoid]: Monoid[Either[A, B]]
implicit def mapMonoid[A, B: Monoid]: Monoid[Map[A, B]]
implicit def futureMonoid[A: Monoid]: Monoid[Future[A]]
And many more!
Monoids applied
def step(word: String) = (1, word.length, Map(word -> 1))
val data = lines.flatMap(_.split(" ").toList).map(step)
val empty = Monoid[(Int, Int, Map[String, Int])].empty
val (words, chars, wordCount) = data.foldLeft(empty)(_ |+| _)
Monoids applied
def step(word: String) = (1, word.length, Map(word -> 1))
val data = lines.flatMap(_.split(" ").toList).map(step)
val (words, chars, wordCount) = data.combineAll
Monoids applied
def step(word: String) = (1, word.length, Map(word -> 1))
val data = lines.flatMap(_.split(" ").toList).map(step)
val (words, chars, wordCount) = data.combineAll
list.combineAll === list.foldLeft(empty)(_ |+| _)
Monoid laws
1. Associativity:
(x |+| y) |+| z === x |+| (y |+| z)
2. Right identity:
x |+| empty === x
3. Left identity:
empty |+| x === x
Monoid laws in action
(a |+| b |+| c |+| d |+| e |+| f |+| g)
↕
(a |+| b) |+| (c |+| d) |+| (e |+| f) |+| g
↕
(a |+| b) |+| (c |+| d) |+| (e |+| f) |+| (g |+| empty)
We can write a fully parallel version of fold!!
Parallel fold
val grouped: List[List[A]] =
list.grouped(getRuntime.availableProcessors)
val innerFolded: List[A] =
grouped.parallelMap(_.combineAll)
val result: A =
innerFolded.combineAll
Let’s talk about Functors
@typeclass
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
List(1, 2, 3).map(_.toString)
Option(42).map(_.toString)
Right(23).map(_.toString)
Vector(-1, 39, 11).map(_.toString)
Future(22).map(_.toString)
Let’s talk about Monoidal Functors
(A |+| A): A
(F[A] |+| F[A]): F[A]
(F[A] |@| F[B]): F[???]
Let’s talk about Monoidal Functors
(A |+| A): A
(F[A] |+| F[A]): F[A]
(F[A] |@| F[B]): F[(A, B)]
Let’s talk about Monoidal Functors
@typeclass
trait Monoidal[F[_]] extends Functor[F] {
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
def pure[A](a: A): F[A]
}
implicit val optionMonoidal: Monoidal[Option]
implicit val futureMonoidal: Monoidal[Future]
Generalizing Future.sequence
object Future {
def sequence[A](l: List[Future[A]]): Future[List[A]]
}
Generalizing Future.sequence
def sequence[A](l: List[Future[A]]): Future[List[A]]
def sequence[F[_]: Monoidal, A](l: List[F[A]]): F[List[A]] =
l.foldRight(Monoidal[F].pure(List.empty[A]))
{ (fa: F[A], acc: F[List[A]]) =>
val prod: F[(A, List[A])] = fa.product(acc)
prod.map(_ +: _)
}
Generalizing Future.sequence
def sequence[A](l: List[Future[A]]): Future[List[A]]
def sequence[F[_]: Monoidal, A](l: List[F[A]]): F[List[A]] =
l.foldRight(Monoidal[F].pure(List.empty[A]))
{ (fa: F[A], acc: F[List[A]]) =>
val prod: F[(A, List[A])] = fa.product(acc)
prod.map(_ +: _)
}
Generalizing Future.sequence
def sequence[A](l: List[Future[A]]): Future[List[A]]
def sequence[F[_]: Monoidal, A](l: List[F[A]]): F[List[A]] =
l.foldRight(Monoidal[F].pure(List.empty[A]))
{ (fa: F[A], acc: F[List[A]]) =>
(fa, acc).mapN(_ +: _)
}
Generalizing Future.sequence
def sequence[A](l: List[Future[A]]): Future[List[A]]
def sequence[F[_]: Monoidal, A](l: List[F[A]]): F[List[A]] =
l.foldRight(Monoidal[F].pure(List.empty[A]))
{ (fa: F[A], acc: F[List[A]]) =>
(fa, acc).mapN(_ +: _)
}
fa.product(fb).map(f) === (fa, fb).mapN(f)
Generalizing Future.traverse
def traverse[A, B](l: List[A])(f: A => Future[B]): Future[List[B]]
def traverse[F[_]: Monoidal, A, B](l: List[A])(f: A => F[B]): F[List[B] =
l.foldRight(Monoidal[F].pure(List.empty[B]))
{ (a: A, acc: F[List[B]]) =>
(acc, f(a)).mapN(_ :+ _)
}
l.traverse(f) === l.map(f).sequence
The laws remain the same
1. Associativity:
(fa product fb) product fc ~ fa product (fb product fc)
2. Right identity:
fa product pure(()) ~ fa
3. Left identity:
pure(()) product fa ~ fa
A tiny secret
What we called Monoidal so far, is usually called Applicative in
programmer’s circles.
I personally think Monoidal is the better name as it describes the
relationship to Monoids much better, but for the sake of consistency
we’ll use Applicative.
The Foldable type class
So far we used List everywhere, but what about Vector, Stream, etc?
@typeclass
trait Foldable[F[_]] {
def foldMap[A, M: Monoid](fa: F[A])(f: A => M): M
def combineAll[M: Monoid](fa: F[M]): M = foldMap(identity)
}
implicit val listFoldable: Foldable[List]
implicit def vectorFoldable: Foldable[Vector]
implicit def optionFoldable: Foldable[Option]
The Traverse type class
@typeclass
trait Traverse[T[_]] extends Foldable[T] with Functor[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]]
}
implicit def vectorTraversable: Traverse[Vector]
implicit def optionTraversable: Traverse[Option]
type EitherString[A] = Either[String, A]
implicit def eitherStringTraversable: Traverse[EitherString]
The Traverse type class
@typeclass
trait Traverse[T[_]] extends Foldable[T] with Functor[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]]
}
implicit def vectorTraversable: Traverse[Vector]
implicit def optionTraversable: Traverse[Option]
implicit def eitherStringTraversable[E]: Traverse[Either[E, ?]]
The Traverse type class
List[Future[A]] => Future[List[A]]
Stream[Option[A]] => Option[Stream[A]]
Either[E, IO[A]] => IO[Either[E, A]]
Vector[ValidatedNel[Error, A]] => ValidatedNel[Error, Vector[A]]
ValidatedNel???
sealed trait Validated[+E, +A]
case class Valid[+A](a: A) extends Validated[Nothing, A]
case class Invalid[+E](e: E) extends Validated[E, Nothing]
type ValidatedNel[E, A] = Validated[NonEmptyList[E], A]
def validate(u: String): ValidatedNel[Error, User]
val users: ValidatedNel[Error, List[User]] = lines.traverse(validate)
Still not convinced?
Still not convinced?
Still not convinced?
Still not convinced?
Bonus: Semigroups!
@typeclass
trait Semigroup[T] {
def combine(a: T, b: T): T
}
Semigroups describe an associative binary operation.
@typeclass
trait Monoid[T] extends Semigroup[T] {
def empty: T
}
Bonus: Semigroups!
List().max
// java.lang.UnsupportedOperationException: empty.max
List().reduce(_ |+| _)
// java.lang.UnsupportedOperationException: empty.reduceLeft
NonEmptyList()
// not enough arguments for method apply: (head: A, tail: A*)
NonEmptyList(1, 2).maximum
// res0: Int = 2
NonEmptyList(1, 2, 3, 4).reduce(_ |+| _)
// res1: Int = 7
… and Semigroupal Functors!
@typeclass
trait Semigroupal[F[_]] extends Functor[F] {
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}
@typeclass
trait Monoidal[F[_]] extends Semigroupal[F] {
def pure[A](a: A): F[A]
}
… and Semigroupal Functors!
@typeclass
trait Apply[F[_]] extends Functor[F] {
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}
@typeclass
trait Applicative[F[_]] extends Semigroupal[F] {
def pure[A](a: A): F[A]
}
… and Semigroupal Functors!
implicit def mapApplicative[K] = new Applicative[Map[K, ?]] {
def pure[V](v: V): Map[K, V] = ???
// ...
}
It doesn’t work!
implicit def mapApply[K] = new Apply[Map[K, ?]] {
// ...
}
This does! :)
Conclusions
Today, we learned about Monoids, Functors,
Monoidal/Applicative Functors and Foldables.
We also learned about NonEmptyLists and Validated.
And of course, we learned about the almighty power of
traverse!
I Hope this was a good gateway drug to the cats library.
Thank you for
listening!
Twitter: @LukaJacobowitz
GitHub: LukaJCB

Mais conteúdo relacionado

Mais procurados

N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...Philip Schwarz
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2Hang Zhao
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Philip Schwarz
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator PatternEric Torreborre
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)stasimus
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adtsHang Zhao
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final TaglessJohn De Goes
 
Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)stasimus
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadOliver Daff
 
Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1Hang Zhao
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type ClassesJohn De Goes
 
Scala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsScala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsKirill Kozlov
 
The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)Eric Torreborre
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New GameJohn De Goes
 
Monoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and CatsMonoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and CatsPhilip Schwarz
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't FreeKelley Robinson
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala Knoldus Inc.
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The WildStackMob Inc
 

Mais procurados (20)

N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adts
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final Tagless
 
Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And Monad
 
Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
 
Scala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsScala. Introduction to FP. Monads
Scala. Introduction to FP. Monads
 
The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New Game
 
Monoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and CatsMonoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and Cats
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't Free
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
 

Semelhante a Oh, All the things you'll traverse

Algebraic Data Types and Origami Patterns
Algebraic Data Types and Origami PatternsAlgebraic Data Types and Origami Patterns
Algebraic Data Types and Origami PatternsVasil Remeniuk
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystifiedAlessandro Lacava
 
Power of functions in a typed world
Power of functions in a typed worldPower of functions in a typed world
Power of functions in a typed worldDebasish Ghosh
 
Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2Hang Zhao
 
Sequence and Traverse - Part 3
Sequence and Traverse - Part 3Sequence and Traverse - Part 3
Sequence and Traverse - Part 3Philip Schwarz
 
An Introduction to Functional Programming using Haskell
An Introduction to Functional Programming using HaskellAn Introduction to Functional Programming using Haskell
An Introduction to Functional Programming using HaskellMichel Rijnders
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceAlexey Raga
 
Types by Adform Research
Types by Adform ResearchTypes by Adform Research
Types by Adform ResearchVasil Remeniuk
 
High Wizardry in the Land of Scala
High Wizardry in the Land of ScalaHigh Wizardry in the Land of Scala
High Wizardry in the Land of Scaladjspiewak
 
Generic Functional Programming with Type Classes
Generic Functional Programming with Type ClassesGeneric Functional Programming with Type Classes
Generic Functional Programming with Type ClassesTapio Rautonen
 
Scala Type Classes: Basics and More
Scala Type Classes:  Basics and MoreScala Type Classes:  Basics and More
Scala Type Classes: Basics and Moresukanthajra
 

Semelhante a Oh, All the things you'll traverse (20)

Algebraic Data Types and Origami Patterns
Algebraic Data Types and Origami PatternsAlgebraic Data Types and Origami Patterns
Algebraic Data Types and Origami Patterns
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystified
 
Power of functions in a typed world
Power of functions in a typed worldPower of functions in a typed world
Power of functions in a typed world
 
Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2
 
Thesis PPT
Thesis PPTThesis PPT
Thesis PPT
 
Thesis
ThesisThesis
Thesis
 
Sequence and Traverse - Part 3
Sequence and Traverse - Part 3Sequence and Traverse - Part 3
Sequence and Traverse - Part 3
 
Monoids
MonoidsMonoids
Monoids
 
Monoids
MonoidsMonoids
Monoids
 
An Introduction to Functional Programming using Haskell
An Introduction to Functional Programming using HaskellAn Introduction to Functional Programming using Haskell
An Introduction to Functional Programming using Haskell
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritance
 
Types by Adform Research
Types by Adform ResearchTypes by Adform Research
Types by Adform Research
 
Scala jargon cheatsheet
Scala jargon cheatsheetScala jargon cheatsheet
Scala jargon cheatsheet
 
Functional programming in scala
Functional programming in scalaFunctional programming in scala
Functional programming in scala
 
Frp2016 3
Frp2016 3Frp2016 3
Frp2016 3
 
High Wizardry in the Land of Scala
High Wizardry in the Land of ScalaHigh Wizardry in the Land of Scala
High Wizardry in the Land of Scala
 
Generic Functional Programming with Type Classes
Generic Functional Programming with Type ClassesGeneric Functional Programming with Type Classes
Generic Functional Programming with Type Classes
 
From OOP To FP Through A Practical Case
From OOP To FP Through A Practical CaseFrom OOP To FP Through A Practical Case
From OOP To FP Through A Practical Case
 
Typeclasses
TypeclassesTypeclasses
Typeclasses
 
Scala Type Classes: Basics and More
Scala Type Classes:  Basics and MoreScala Type Classes:  Basics and More
Scala Type Classes: Basics and More
 

Mais de Luka Jacobowitz

Up and Running with the Typelevel Stack
Up and Running with the Typelevel StackUp and Running with the Typelevel Stack
Up and Running with the Typelevel StackLuka Jacobowitz
 
Principled Error Handling - Scalapeño
Principled Error Handling - ScalapeñoPrincipled Error Handling - Scalapeño
Principled Error Handling - ScalapeñoLuka Jacobowitz
 
Building a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLBuilding a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLLuka Jacobowitz
 
What Referential Transparency can do for you
What Referential Transparency can do for youWhat Referential Transparency can do for you
What Referential Transparency can do for youLuka Jacobowitz
 
Reactive Programming in the Browser feat. Scala.js and Rx
Reactive Programming in the Browser feat. Scala.js and RxReactive Programming in the Browser feat. Scala.js and Rx
Reactive Programming in the Browser feat. Scala.js and RxLuka Jacobowitz
 
Reactive Programming in the Browser feat. Scala.js and PureScript
Reactive Programming in the Browser feat. Scala.js and PureScriptReactive Programming in the Browser feat. Scala.js and PureScript
Reactive Programming in the Browser feat. Scala.js and PureScriptLuka Jacobowitz
 

Mais de Luka Jacobowitz (7)

Up and Running with the Typelevel Stack
Up and Running with the Typelevel StackUp and Running with the Typelevel Stack
Up and Running with the Typelevel Stack
 
Principled Error Handling - Scalapeño
Principled Error Handling - ScalapeñoPrincipled Error Handling - Scalapeño
Principled Error Handling - Scalapeño
 
Building a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLBuilding a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGL
 
What Referential Transparency can do for you
What Referential Transparency can do for youWhat Referential Transparency can do for you
What Referential Transparency can do for you
 
Scala UA 2017
Scala UA 2017Scala UA 2017
Scala UA 2017
 
Reactive Programming in the Browser feat. Scala.js and Rx
Reactive Programming in the Browser feat. Scala.js and RxReactive Programming in the Browser feat. Scala.js and Rx
Reactive Programming in the Browser feat. Scala.js and Rx
 
Reactive Programming in the Browser feat. Scala.js and PureScript
Reactive Programming in the Browser feat. Scala.js and PureScriptReactive Programming in the Browser feat. Scala.js and PureScript
Reactive Programming in the Browser feat. Scala.js and PureScript
 

Último

Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
How to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdfHow to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdfLivetecs LLC
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprisepreethippts
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Natan Silnitsky
 

Último (20)

Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
How to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdfHow to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdf
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprise
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
 

Oh, All the things you'll traverse

  • 1. Oh, All the things you’ll traverse ScalaDays - Luka Jacobowitz
  • 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. ● Type classes ● Monoids ● Functors ● Traversals Agenda
  • 4. Type classes ● Type classes offer us ad-hoc polymorphism ● Operate on types rather than instances ● Pretty similar to OOP interfaces (traits) ● No explicit language support in Scala... (yet)
  • 5. A small type class example @typeclass trait Show[T] { def show(value: T): String } implicit val showString: Show[String] = new Show[String] { def show(value: String): String = value } implicit val showInt: Show[Int] = _.toString def emptyIfFalse[T: Show](t: T, f: T => Boolean): String = if (f(t)) t.show else “”
  • 6. Something a bit more useful @typeclass trait Monoid[T] { def empty: T def combine(a: T, b: T): T } implicit val monoidInt: Monoid[Int] = new Monoid[Int] { def empty: Int = 0 def combine(a: Int, b: Int): Int = a + b }
  • 7. Something a bit more useful def sumInt(list: List[Int]): Int = list.foldLeft(0)(_ + _) def sumString(list: List[String]): String = list.foldLeft("")(_ + _) def sumSet[T](list: List[Set[T]]): Set[T] = list.foldLeft(Set.empty[T])(_ union _) def sum[T: Monoid](list: List[T]): T = list.foldLeft(Monoid[T].empty)(_ combine _)
  • 8. Something a bit more useful def sumInt(list: List[Int]): Int = list.foldLeft(0)(_ + _) def sumString(list: List[String]): String = list.foldLeft("")(_ + _) def sumSet[T](list: List[Set[T]]): Set[T] = list.foldLeft(Set.empty[T])(_ union _) def sum[T: Monoid](list: List[T]): T = list.foldLeft(Monoid[T].empty)(_ combine _)
  • 9. Implicit derivation implicit def optionMonoid[T: Monoid] = new Monoid[Option[T]] { def empty = None def combine(a: Option[T], b: Option[T]) = (a, b) match { case (Some(x), Some(y)) => Some(x |+| y) case (Some(x), None) => Some(x) case (None, Some(y)) => Some(y) case (None, None) => None } }
  • 10. Type classes vs subtyping ● Type classes give us operations on types instead of on values ● This comes in handy when dealing with type classes like Monoids ● We can use type classes to derive instances for data types that might hold other data types when they also have instances.
  • 11. Monoids everywhere implicit def functionMonoid[A, B: Monoid] = new Monoid[A => B] { def empty = _ => Monoid[B].empty def combine(x: A => B, y: A => B): A => B = a => x(a) |+| y(a) } implicit def tupleMonoid[A: Monoid, B: Monoid] = new Monoid[(A, B)] { def empty = (Monoid[A].empty, Monoid[B].empty) def combine(x: (A, B), y: (A, B)): (A, B) = (x._1 |+| y._1, x._2 |+| y._2) }
  • 12. Monoids everywhere implicit def eitherMonoid[A, B: Monoid]: Monoid[Either[A, B]] implicit def mapMonoid[A, B: Monoid]: Monoid[Map[A, B]] implicit def futureMonoid[A: Monoid]: Monoid[Future[A]] And many more!
  • 13. Monoids applied def step(word: String) = (1, word.length, Map(word -> 1)) val data = lines.flatMap(_.split(" ").toList).map(step) val empty = Monoid[(Int, Int, Map[String, Int])].empty val (words, chars, wordCount) = data.foldLeft(empty)(_ |+| _)
  • 14. Monoids applied def step(word: String) = (1, word.length, Map(word -> 1)) val data = lines.flatMap(_.split(" ").toList).map(step) val (words, chars, wordCount) = data.combineAll
  • 15. Monoids applied def step(word: String) = (1, word.length, Map(word -> 1)) val data = lines.flatMap(_.split(" ").toList).map(step) val (words, chars, wordCount) = data.combineAll list.combineAll === list.foldLeft(empty)(_ |+| _)
  • 16. Monoid laws 1. Associativity: (x |+| y) |+| z === x |+| (y |+| z) 2. Right identity: x |+| empty === x 3. Left identity: empty |+| x === x
  • 17. Monoid laws in action (a |+| b |+| c |+| d |+| e |+| f |+| g) ↕ (a |+| b) |+| (c |+| d) |+| (e |+| f) |+| g ↕ (a |+| b) |+| (c |+| d) |+| (e |+| f) |+| (g |+| empty) We can write a fully parallel version of fold!!
  • 18. Parallel fold val grouped: List[List[A]] = list.grouped(getRuntime.availableProcessors) val innerFolded: List[A] = grouped.parallelMap(_.combineAll) val result: A = innerFolded.combineAll
  • 19. Let’s talk about Functors @typeclass trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } List(1, 2, 3).map(_.toString) Option(42).map(_.toString) Right(23).map(_.toString) Vector(-1, 39, 11).map(_.toString) Future(22).map(_.toString)
  • 20. Let’s talk about Monoidal Functors (A |+| A): A (F[A] |+| F[A]): F[A] (F[A] |@| F[B]): F[???]
  • 21. Let’s talk about Monoidal Functors (A |+| A): A (F[A] |+| F[A]): F[A] (F[A] |@| F[B]): F[(A, B)]
  • 22. Let’s talk about Monoidal Functors @typeclass trait Monoidal[F[_]] extends Functor[F] { def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] def pure[A](a: A): F[A] } implicit val optionMonoidal: Monoidal[Option] implicit val futureMonoidal: Monoidal[Future]
  • 23. Generalizing Future.sequence object Future { def sequence[A](l: List[Future[A]]): Future[List[A]] }
  • 24. Generalizing Future.sequence def sequence[A](l: List[Future[A]]): Future[List[A]] def sequence[F[_]: Monoidal, A](l: List[F[A]]): F[List[A]] = l.foldRight(Monoidal[F].pure(List.empty[A])) { (fa: F[A], acc: F[List[A]]) => val prod: F[(A, List[A])] = fa.product(acc) prod.map(_ +: _) }
  • 25. Generalizing Future.sequence def sequence[A](l: List[Future[A]]): Future[List[A]] def sequence[F[_]: Monoidal, A](l: List[F[A]]): F[List[A]] = l.foldRight(Monoidal[F].pure(List.empty[A])) { (fa: F[A], acc: F[List[A]]) => val prod: F[(A, List[A])] = fa.product(acc) prod.map(_ +: _) }
  • 26. Generalizing Future.sequence def sequence[A](l: List[Future[A]]): Future[List[A]] def sequence[F[_]: Monoidal, A](l: List[F[A]]): F[List[A]] = l.foldRight(Monoidal[F].pure(List.empty[A])) { (fa: F[A], acc: F[List[A]]) => (fa, acc).mapN(_ +: _) }
  • 27. Generalizing Future.sequence def sequence[A](l: List[Future[A]]): Future[List[A]] def sequence[F[_]: Monoidal, A](l: List[F[A]]): F[List[A]] = l.foldRight(Monoidal[F].pure(List.empty[A])) { (fa: F[A], acc: F[List[A]]) => (fa, acc).mapN(_ +: _) } fa.product(fb).map(f) === (fa, fb).mapN(f)
  • 28. Generalizing Future.traverse def traverse[A, B](l: List[A])(f: A => Future[B]): Future[List[B]] def traverse[F[_]: Monoidal, A, B](l: List[A])(f: A => F[B]): F[List[B] = l.foldRight(Monoidal[F].pure(List.empty[B])) { (a: A, acc: F[List[B]]) => (acc, f(a)).mapN(_ :+ _) } l.traverse(f) === l.map(f).sequence
  • 29. The laws remain the same 1. Associativity: (fa product fb) product fc ~ fa product (fb product fc) 2. Right identity: fa product pure(()) ~ fa 3. Left identity: pure(()) product fa ~ fa
  • 30. A tiny secret What we called Monoidal so far, is usually called Applicative in programmer’s circles. I personally think Monoidal is the better name as it describes the relationship to Monoids much better, but for the sake of consistency we’ll use Applicative.
  • 31. The Foldable type class So far we used List everywhere, but what about Vector, Stream, etc? @typeclass trait Foldable[F[_]] { def foldMap[A, M: Monoid](fa: F[A])(f: A => M): M def combineAll[M: Monoid](fa: F[M]): M = foldMap(identity) } implicit val listFoldable: Foldable[List] implicit def vectorFoldable: Foldable[Vector] implicit def optionFoldable: Foldable[Option]
  • 32. The Traverse type class @typeclass trait Traverse[T[_]] extends Foldable[T] with Functor[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]] } implicit def vectorTraversable: Traverse[Vector] implicit def optionTraversable: Traverse[Option] type EitherString[A] = Either[String, A] implicit def eitherStringTraversable: Traverse[EitherString]
  • 33. The Traverse type class @typeclass trait Traverse[T[_]] extends Foldable[T] with Functor[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]] } implicit def vectorTraversable: Traverse[Vector] implicit def optionTraversable: Traverse[Option] implicit def eitherStringTraversable[E]: Traverse[Either[E, ?]]
  • 34. The Traverse type class List[Future[A]] => Future[List[A]] Stream[Option[A]] => Option[Stream[A]] Either[E, IO[A]] => IO[Either[E, A]] Vector[ValidatedNel[Error, A]] => ValidatedNel[Error, Vector[A]]
  • 35. ValidatedNel??? sealed trait Validated[+E, +A] case class Valid[+A](a: A) extends Validated[Nothing, A] case class Invalid[+E](e: E) extends Validated[E, Nothing] type ValidatedNel[E, A] = Validated[NonEmptyList[E], A] def validate(u: String): ValidatedNel[Error, User] val users: ValidatedNel[Error, List[User]] = lines.traverse(validate)
  • 40. Bonus: Semigroups! @typeclass trait Semigroup[T] { def combine(a: T, b: T): T } Semigroups describe an associative binary operation. @typeclass trait Monoid[T] extends Semigroup[T] { def empty: T }
  • 41. Bonus: Semigroups! List().max // java.lang.UnsupportedOperationException: empty.max List().reduce(_ |+| _) // java.lang.UnsupportedOperationException: empty.reduceLeft NonEmptyList() // not enough arguments for method apply: (head: A, tail: A*) NonEmptyList(1, 2).maximum // res0: Int = 2 NonEmptyList(1, 2, 3, 4).reduce(_ |+| _) // res1: Int = 7
  • 42. … and Semigroupal Functors! @typeclass trait Semigroupal[F[_]] extends Functor[F] { def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] } @typeclass trait Monoidal[F[_]] extends Semigroupal[F] { def pure[A](a: A): F[A] }
  • 43. … and Semigroupal Functors! @typeclass trait Apply[F[_]] extends Functor[F] { def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] } @typeclass trait Applicative[F[_]] extends Semigroupal[F] { def pure[A](a: A): F[A] }
  • 44. … and Semigroupal Functors! implicit def mapApplicative[K] = new Applicative[Map[K, ?]] { def pure[V](v: V): Map[K, V] = ??? // ... } It doesn’t work! implicit def mapApply[K] = new Apply[Map[K, ?]] { // ... } This does! :)
  • 45. Conclusions Today, we learned about Monoids, Functors, Monoidal/Applicative Functors and Foldables. We also learned about NonEmptyLists and Validated. And of course, we learned about the almighty power of traverse! I Hope this was a good gateway drug to the cats library.
  • 46. Thank you for listening! Twitter: @LukaJacobowitz GitHub: LukaJCB