SlideShare a Scribd company logo
1 of 6
Download to read offline
a sighting of
traverseFilter
and foldMap in
@philip_schwarz
slides by http://fpilluminated.com/
by
trait ShoppingCart[F[_]] {
def add(userId: UserId, itemId: ItemId, quantity: Quantity): F[Unit]
def get(userId: UserId): F[CartTotal]
def delete(userId: UserId): F[Unit]
def removeItem(userId: UserId, itemId: ItemId): F[Unit]
def update(userId: UserId, cart: Cart): F[Unit]
}
object ShoppingCart {
def make[F[_]: GenUUID: MonadThrow](
items: Items[F],
redis: RedisCommands[F, String, String],
exp: ShoppingCartExpiration
): ShoppingCart[F] = new ShoppingCart[F] {
override def add(userId: UserId, itemId: ItemId, quantity: Quantity): F[Unit] =
redis.hSet(userId.show, itemId.show, quantity.show) *>
redis.expire(userId.show, exp.value).void
override def get(userId: UserId): F[CartTotal] =
redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] =>
itemIdToQuantityMap.toList
.traverseFilter { case (id, qty) =>
for {
itemId <- ID.read[F, ItemId](id)
quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt))
maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity)))
} yield maybeCartItem
}
.map { items =>
CartTotal(items, items.foldMap(_.subTotal))
}
}
…
}
}
with some minor renaming, to ease comprehension
for anyone lacking context – see repo for original
override def get(userId: UserId): F[CartTotal] =
redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] =>
itemIdToQuantityMap.toList
.traverseFilter { case (id, qty) =>
for {
itemId <- ID.read[F, ItemId](id)
quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt))
maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity)))
} yield maybeCartItem
}
.map { items =>
CartTotal(items, items.foldMap(_.subTotal))
}
}
override def get(userId: UserId): F[CartTotal] =
redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] =>
itemIdToQuantityMap.toList
.traverseFilter { case (id, qty) =>
for {
itemId <- ID.read[F, ItemId](id)
quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt))
maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity)))
} yield maybeCartItem
}
.map { items =>
CartTotal(items, items.foldMap(_.subTotal))
}
}
^⇧P Type Info
^⇧P Type Info
override def get(userId: UserId): F[CartTotal] =
redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] =>
itemIdToQuantityMap.toList
.traverseFilter { case (id, qty) =>
for {
itemId <- ID.read[F, ItemId](id)
quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt))
maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity)))
} yield maybeCartItem
}
.map { items: List[cart.CartItem] =>
CartTotal(items, items.foldMap(_.subTotal))
}
}
override def get(userId: UserId): F[CartTotal] =
redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] =>
itemIdToQuantityMap.toList
.traverseFilter { case (id, qty) =>
for {
itemId <- ID.read[F, ItemId](id)
quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt))
maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity)))
} yield maybeCartItem
}
.map { items: List[cart.CartItem] =>
CartTotal(items, items.foldMap(_.subTotal))
}
}
^⇧P Type Info
^⇧P Type Info
@typeclass trait TraverseFilter[F[_]] extends FunctorFilter[F] {
…
A combined traverse and filter. Filtering is handled via Option instead of Boolean such that the
output type B can be different than the input type A.
def traverseFilter[G[_], A, B](fa: F[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[F[B]]
List[(String,String)] => ((String,String) => F[Option[CartItem]]) => F[List[CartItem]]
def make[F[_]: GenUUID: MonadThrow]
type MonadThrow[F[_]] = MonadError[F, Throwable]
An applicative that also allows you to raise and or handle an error value.
This type class allows one to abstract over error-handling applicatives.
trait ApplicativeError[F[_], E] extends Applicative[F] { …
This type class allows one to abstract over error-handling monads.
trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] { …
Applicative
Monad
Functor
TraverseFilter
FunctorFilter
ApplicativeError
MonadError
FunctorFilter[F] allows you to map and filter out elements simultaneously.
@typeclass trait FunctorFilter[F[_]] extends Serializable
TraverseFilter, also known as Witherable, represents list-like structures
that can essentially have a traverse and a filter applied as a single
combined operation (traverseFilter).
@typeclass trait TraverseFilter[F[_]] extends FunctorFilter[F] {
Traverse
Foldable
trait ShoppingCart[F[_]] {
def add(userId: UserId, itemId: ItemId, quantity: Quantity): F[Unit]
def get(userId: UserId): F[CartTotal]
def delete(userId: UserId): F[Unit]
def removeItem(userId: UserId, itemId: ItemId): F[Unit]
def update(userId: UserId, cart: Cart): F[Unit]
}
object ShoppingCart {
def make[F[_]: GenUUID: MonadThrow](
items: Items[F],
redis: RedisCommands[F, String, String],
exp: ShoppingCartExpiration
): ShoppingCart[F] = new ShoppingCart[F] {
override def add(userId: UserId, itemId: ItemId, quantity: Quantity): F[Unit] =
redis.hSet(userId.show, itemId.show, quantity.show) *>
redis.expire(userId.show, exp.value).void
override def get(userId: UserId): F[CartTotal] =
redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] =>
itemIdToQuantityMap.toList
.traverseFilter { case (id, qty) =>
for {
itemId <- ID.read[F, ItemId](id)
quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt))
maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity)))
} yield maybeCartItem
}
.map { items: List[cart.CartItem] =>
CartTotal(items, items.foldMap(_.subTotal))
}
}
…
}
}
override def get(userId: UserId): F[CartTotal] =
redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] =>
itemIdToQuantityMap.toList
.traverseFilter { case (id, qty) =>
for {
itemId <- ID.read[F, ItemId](id)
quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt))
maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity)))
} yield maybeCartItem
}
.map { items =>
CartTotal(items, items.foldMap(_.subTotal))
}
}
⇧⌘P Show implicit arguments
trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] {
…
Fold implemented by mapping A values into B and then
combining them using the given Monoid[B] instance.
def foldMap[A, B](fa: F[A])(f: A => B)(implicit B: Monoid[B]): B =
foldLeft(fa, B.empty)((b, a) => B.combine(b, f(a)))
^⇧P Type Info
⌘P Parameter Info
override def get(userId: UserId): F[CartTotal] =
redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] =>
itemIdToQuantityMap.toList
.traverseFilter { case (id, qty) =>
for {
itemId <- ID.read[F, ItemId](id)
quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt))
maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity)))
} yield maybeCartItem
}
.map { items =>
CartTotal(items, items.foldMap(_.subTotal))(moneyMonoid)
}
}
implicit val moneyMonoid: Monoid[Money] =
new Monoid[Money] {
override def empty: Money = USD(0)
override def combine(x: Money, y: Money): Money = x + y
}
case class CartItem(item: Item, quantity: Quantity) {
def subTotal: Money = USD(item.price.amount * quantity.value)
}
List[CartItem] => (CartItem => Money) => Monoid[Money] => Money
A monoid is a semigroup with an identity. A monoid is a specialization of a
semigroup, so its operation must be associative. Additionally, combine(x,
empty) == combine(empty, x) == x. For example, if we have Monoid[String],
with combine as string concatenation, then empty = "".
trait Monoid[@sp(Int, Long, Float, Double) A] extends Any with Semigroup[A] {
A semigroup is any set A with an associative operation (combine).
trait Semigroup[@sp(Int, Long, Float, Double) A] extends Any with Serializable {
Semigroup
Monoid
final class Money private
(val amount: BigDecimal)
(val currency: Currency)
extends Quantity[Money] {

More Related Content

Similar to A sighting of traverseFilter and foldMap in Practical FP in Scala

The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator PatternEric Torreborre
 
Algebraic Data Types and Origami Patterns
Algebraic Data Types and Origami PatternsAlgebraic Data Types and Origami Patterns
Algebraic Data Types and Origami PatternsVasil Remeniuk
 
Practical scalaz
Practical scalazPractical scalaz
Practical scalazoxbow_lakes
 
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
 
12.9 Program Online shopping cart (continued) (C++)This program e.pdf
12.9 Program Online shopping cart (continued) (C++)This program e.pdf12.9 Program Online shopping cart (continued) (C++)This program e.pdf
12.9 Program Online shopping cart (continued) (C++)This program e.pdffasttracksunglass
 
Blending Culture in Twitter Client
Blending Culture in Twitter ClientBlending Culture in Twitter Client
Blending Culture in Twitter ClientKenji Tanaka
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form componentSamuel ROZE
 
Essence of the iterator pattern
Essence of the iterator patternEssence of the iterator pattern
Essence of the iterator patternMarkus Klink
 
Improving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con BerlinImproving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con BerlinIain Hull
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and EffectsRaymond Roestenburg
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional ProgrammingLuka Jacobowitz
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFabio Collini
 
Functional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesFunctional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesAndrás Papp
 
Functional programming in Scala: From error handling to fp
Functional programming in Scala: From error handling to fpFunctional programming in Scala: From error handling to fp
Functional programming in Scala: From error handling to fpJordi Pradel
 
Data type a la carte
Data type a la carteData type a la carte
Data type a la carteYun-Yan Chi
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsŁukasz Chruściel
 
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
 
Monads - Dublin Scala meetup
Monads - Dublin Scala meetupMonads - Dublin Scala meetup
Monads - Dublin Scala meetupMikhail Girkin
 

Similar to A sighting of traverseFilter and foldMap in Practical FP in Scala (20)

Thesis
ThesisThesis
Thesis
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
 
Algebraic Data Types and Origami Patterns
Algebraic Data Types and Origami PatternsAlgebraic Data Types and Origami Patterns
Algebraic Data Types and Origami Patterns
 
Practical scalaz
Practical scalazPractical scalaz
Practical scalaz
 
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)
 
12.9 Program Online shopping cart (continued) (C++)This program e.pdf
12.9 Program Online shopping cart (continued) (C++)This program e.pdf12.9 Program Online shopping cart (continued) (C++)This program e.pdf
12.9 Program Online shopping cart (continued) (C++)This program e.pdf
 
Blending Culture in Twitter Client
Blending Culture in Twitter ClientBlending Culture in Twitter Client
Blending Culture in Twitter Client
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
Essence of the iterator pattern
Essence of the iterator patternEssence of the iterator pattern
Essence of the iterator pattern
 
Bar graph
Bar graphBar graph
Bar graph
 
Improving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con BerlinImproving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con Berlin
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and Effects
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
 
Functional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesFunctional programming techniques in real-world microservices
Functional programming techniques in real-world microservices
 
Functional programming in Scala: From error handling to fp
Functional programming in Scala: From error handling to fpFunctional programming in Scala: From error handling to fp
Functional programming in Scala: From error handling to fp
 
Data type a la carte
Data type a la carteData type a la carte
Data type a la carte
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patterns
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)
 
Monads - Dublin Scala meetup
Monads - Dublin Scala meetupMonads - Dublin Scala meetup
Monads - Dublin Scala meetup
 

More from Philip Schwarz

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
 
Folding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesFolding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesPhilip Schwarz
 
Folding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesFolding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesPhilip Schwarz
 
Folding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesFolding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesPhilip Schwarz
 
Scala Left Fold Parallelisation - Three Approaches
Scala Left Fold Parallelisation- Three ApproachesScala Left Fold Parallelisation- Three Approaches
Scala Left Fold Parallelisation - Three ApproachesPhilip Schwarz
 
Tagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsTagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsPhilip Schwarz
 
Fusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsFusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsPhilip Schwarz
 
A sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaA sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaPhilip Schwarz
 
N-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsN-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsPhilip Schwarz
 
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Philip Schwarz
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...Philip Schwarz
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an examplePhilip Schwarz
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an examplePhilip Schwarz
 
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...Philip Schwarz
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...Philip Schwarz
 
Jordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsJordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsPhilip Schwarz
 
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Philip Schwarz
 
Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...Philip Schwarz
 
The Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor correctionsThe Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor correctionsPhilip Schwarz
 

More from Philip Schwarz (20)

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
 
Folding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesFolding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a series
 
Folding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesFolding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a series
 
Folding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesFolding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a series
 
Scala Left Fold Parallelisation - Three Approaches
Scala Left Fold Parallelisation- Three ApproachesScala Left Fold Parallelisation- Three Approaches
Scala Left Fold Parallelisation - Three Approaches
 
Tagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsTagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also Programs
 
Fusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsFusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with Views
 
A sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaA sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in Scala
 
N-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsN-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets Cats
 
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
 
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
 
Jordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsJordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axioms
 
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
 
Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...
 
The Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor correctionsThe Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor corrections
 

Recently uploaded

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
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
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
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
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
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
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
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
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
 

Recently uploaded (20)

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
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
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
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
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
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
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
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
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
 

A sighting of traverseFilter and foldMap in Practical FP in Scala

  • 1. a sighting of traverseFilter and foldMap in @philip_schwarz slides by http://fpilluminated.com/ by
  • 2. trait ShoppingCart[F[_]] { def add(userId: UserId, itemId: ItemId, quantity: Quantity): F[Unit] def get(userId: UserId): F[CartTotal] def delete(userId: UserId): F[Unit] def removeItem(userId: UserId, itemId: ItemId): F[Unit] def update(userId: UserId, cart: Cart): F[Unit] } object ShoppingCart { def make[F[_]: GenUUID: MonadThrow]( items: Items[F], redis: RedisCommands[F, String, String], exp: ShoppingCartExpiration ): ShoppingCart[F] = new ShoppingCart[F] { override def add(userId: UserId, itemId: ItemId, quantity: Quantity): F[Unit] = redis.hSet(userId.show, itemId.show, quantity.show) *> redis.expire(userId.show, exp.value).void override def get(userId: UserId): F[CartTotal] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] => itemIdToQuantityMap.toList .traverseFilter { case (id, qty) => for { itemId <- ID.read[F, ItemId](id) quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt)) maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity))) } yield maybeCartItem } .map { items => CartTotal(items, items.foldMap(_.subTotal)) } } … } } with some minor renaming, to ease comprehension for anyone lacking context – see repo for original
  • 3. override def get(userId: UserId): F[CartTotal] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] => itemIdToQuantityMap.toList .traverseFilter { case (id, qty) => for { itemId <- ID.read[F, ItemId](id) quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt)) maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity))) } yield maybeCartItem } .map { items => CartTotal(items, items.foldMap(_.subTotal)) } } override def get(userId: UserId): F[CartTotal] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] => itemIdToQuantityMap.toList .traverseFilter { case (id, qty) => for { itemId <- ID.read[F, ItemId](id) quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt)) maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity))) } yield maybeCartItem } .map { items => CartTotal(items, items.foldMap(_.subTotal)) } } ^⇧P Type Info ^⇧P Type Info
  • 4. override def get(userId: UserId): F[CartTotal] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] => itemIdToQuantityMap.toList .traverseFilter { case (id, qty) => for { itemId <- ID.read[F, ItemId](id) quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt)) maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity))) } yield maybeCartItem } .map { items: List[cart.CartItem] => CartTotal(items, items.foldMap(_.subTotal)) } } override def get(userId: UserId): F[CartTotal] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] => itemIdToQuantityMap.toList .traverseFilter { case (id, qty) => for { itemId <- ID.read[F, ItemId](id) quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt)) maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity))) } yield maybeCartItem } .map { items: List[cart.CartItem] => CartTotal(items, items.foldMap(_.subTotal)) } } ^⇧P Type Info ^⇧P Type Info @typeclass trait TraverseFilter[F[_]] extends FunctorFilter[F] { … A combined traverse and filter. Filtering is handled via Option instead of Boolean such that the output type B can be different than the input type A. def traverseFilter[G[_], A, B](fa: F[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[F[B]] List[(String,String)] => ((String,String) => F[Option[CartItem]]) => F[List[CartItem]] def make[F[_]: GenUUID: MonadThrow] type MonadThrow[F[_]] = MonadError[F, Throwable] An applicative that also allows you to raise and or handle an error value. This type class allows one to abstract over error-handling applicatives. trait ApplicativeError[F[_], E] extends Applicative[F] { … This type class allows one to abstract over error-handling monads. trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] { … Applicative Monad Functor TraverseFilter FunctorFilter ApplicativeError MonadError FunctorFilter[F] allows you to map and filter out elements simultaneously. @typeclass trait FunctorFilter[F[_]] extends Serializable TraverseFilter, also known as Witherable, represents list-like structures that can essentially have a traverse and a filter applied as a single combined operation (traverseFilter). @typeclass trait TraverseFilter[F[_]] extends FunctorFilter[F] { Traverse Foldable
  • 5. trait ShoppingCart[F[_]] { def add(userId: UserId, itemId: ItemId, quantity: Quantity): F[Unit] def get(userId: UserId): F[CartTotal] def delete(userId: UserId): F[Unit] def removeItem(userId: UserId, itemId: ItemId): F[Unit] def update(userId: UserId, cart: Cart): F[Unit] } object ShoppingCart { def make[F[_]: GenUUID: MonadThrow]( items: Items[F], redis: RedisCommands[F, String, String], exp: ShoppingCartExpiration ): ShoppingCart[F] = new ShoppingCart[F] { override def add(userId: UserId, itemId: ItemId, quantity: Quantity): F[Unit] = redis.hSet(userId.show, itemId.show, quantity.show) *> redis.expire(userId.show, exp.value).void override def get(userId: UserId): F[CartTotal] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] => itemIdToQuantityMap.toList .traverseFilter { case (id, qty) => for { itemId <- ID.read[F, ItemId](id) quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt)) maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity))) } yield maybeCartItem } .map { items: List[cart.CartItem] => CartTotal(items, items.foldMap(_.subTotal)) } } … } }
  • 6. override def get(userId: UserId): F[CartTotal] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] => itemIdToQuantityMap.toList .traverseFilter { case (id, qty) => for { itemId <- ID.read[F, ItemId](id) quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt)) maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity))) } yield maybeCartItem } .map { items => CartTotal(items, items.foldMap(_.subTotal)) } } ⇧⌘P Show implicit arguments trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { … Fold implemented by mapping A values into B and then combining them using the given Monoid[B] instance. def foldMap[A, B](fa: F[A])(f: A => B)(implicit B: Monoid[B]): B = foldLeft(fa, B.empty)((b, a) => B.combine(b, f(a))) ^⇧P Type Info ⌘P Parameter Info override def get(userId: UserId): F[CartTotal] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap: Map[String, String] => itemIdToQuantityMap.toList .traverseFilter { case (id, qty) => for { itemId <- ID.read[F, ItemId](id) quantity <- MonadThrow[F].catchNonFatal(Quantity(qty.toInt)) maybeCartItem <- items.findById(itemId).map(_.map(_.cart(quantity))) } yield maybeCartItem } .map { items => CartTotal(items, items.foldMap(_.subTotal))(moneyMonoid) } } implicit val moneyMonoid: Monoid[Money] = new Monoid[Money] { override def empty: Money = USD(0) override def combine(x: Money, y: Money): Money = x + y } case class CartItem(item: Item, quantity: Quantity) { def subTotal: Money = USD(item.price.amount * quantity.value) } List[CartItem] => (CartItem => Money) => Monoid[Money] => Money A monoid is a semigroup with an identity. A monoid is a specialization of a semigroup, so its operation must be associative. Additionally, combine(x, empty) == combine(empty, x) == x. For example, if we have Monoid[String], with combine as string concatenation, then empty = "". trait Monoid[@sp(Int, Long, Float, Double) A] extends Any with Semigroup[A] { A semigroup is any set A with an associative operation (combine). trait Semigroup[@sp(Int, Long, Float, Double) A] extends Any with Serializable { Semigroup Monoid final class Money private (val amount: BigDecimal) (val currency: Currency) extends Quantity[Money] {