SlideShare a Scribd company logo
1 of 25
Download to read offline
Reducing Boilerplate and Combining
Effects:
A Monad Transformer Example
Scala Matsuri - Feb 25th, 2017
Connie Chen
:
Hello
• @coni
• Data Platform team @ Twilio
• @ http://github.com/conniec
• Monad transformers allow different monads to
compose
• Combine effects of monads to create a
SUPER MONAD
• Eg. Future[Option], Future[Either],
Reader[Option]
• In this example, we will use the Cats library...
What are Monad transformers?
Future[Either[A, B]] turns into
EitherT[Future, A, B]
Future[Option[A]] turns into
OptionT[Future, A]
import scala.concurrent.Future
import cats.data.OptionT
import cats.implicits._
import
scala.concurrent.ExecutionContext.Implicits.glo
bal
case class Beans(fresh: Boolean = true)
case class Grounds()
class GroundBeansException(s: String) extends
Exception(s: String)
1.
Example: Making coffee!
Step 1. Grind the beans
def grindFreshBeans(beans: Beans, clumsy: Boolean =
false): Future[Option[Grounds]] = {
if (clumsy) {
Future.failed(new GroundBeansException("We are bad
at grinding"))
} else if (beans.fresh) {
Future.successful(Option(Grounds()))
} else {
Future.successful(None)
}
}
1.
Example: Making coffee!
Step 1. Grind the beans
Step 1. Grind the beans
Three different kind of results:
• Value found
• Value not found
• Future failed
Future 3
Example: Making coffee!
Step 2. Boil hot water
case class Kettle(filled: Boolean = true)
case class Water()
case class Coffee(delicious: Boolean)
class HotWaterException(s: String) extends
Exception(s: String)
2.
def getHotWater(kettle: Kettle, clumsy: Boolean =
false): Future[Option[Water]] = {
if (clumsy) {
Future.failed(new HotWaterException("Ouch
spilled that water!"))
} else if (kettle.filled) {
Future.successful(Option(Water()))
} else {
Future.successful(None)
}
}
Step 3. Combine water and coffee (it's a pourover)
3. ( )
def makingCoffee(grounds: Grounds, water: Water):
Future[Coffee] = {
println(s"Making coffee with... $grounds and
$water")
Future.successful(Coffee(delicious=true))
}
val coffeeFut = for {
} yield Option(result)
coffeeFut.onSuccess {
case Some(s) => println(s"SUCCESS: $s")
case None => println("No coffee found?")
}
coffeeFut.onFailure {
case x => println(s"FAIL: $x")
}
Without Monad transformers, success scenario
beans <- grindFreshBeans(Beans(fresh=true))
hotWater <- getHotWater(Kettle(filled=true))
beansResult = beans.getOrElse(throw new Exception("Beans result
errored. "))
waterResult = hotWater.getOrElse(throw new Exception("Water
result errored. "))
result <- makingCoffee(beansResult, waterResult)
Without Monad transformers, success scenario
coffeeFut:
scala.concurrent.Future[Option[Coffee]] =
scala.concurrent.impl.Promise
$DefaultPromise@7404ac2
scala> Making coffee with... Grounds() and
Water()
SUCCESS: Coffee(true)
With Monad transformers, success scenario
val coffeeFutMonadT = for {
beans <- OptionT(grindFreshBeans(Beans(fresh=true)))
hotWater <- OptionT(getHotWater(Kettle(filled=true)))
result <- OptionT.liftF(makingCoffee(beans, hotWater))
} yield result
coffeeFutMonadT.value.onSuccess {
case Some(s) => println(s"SUCCESS: $s")
case None => println("No coffee found?")
}
coffeeFutMonadT.value.onFailure {
case x => println(s"FAIL: $x")
}
coffeeFutMonadT:
cats.data.OptionT[scala.concurrent.Future,
Coffee] =
OptionT(scala.concurrent.impl.Promise
$DefaultPromise@4a1c4b40)
scala> Making coffee with... Grounds() and
Water()
SUCCESS: Coffee(true)
With Monad transformers, success scenario
OptionT
`fromOption` gives you an OptionT from Option
Internally, it is wrapping your option in a Future.successful()
`liftF` gives you an OptionT from Future
Internally, it is mapping on your Future and wrapping it in a
Some()
Helper functions on OptionT
val coffeeFut = for {
beans <- grindFreshBeans(Beans(fresh=false))
hotWater <- getHotWater(Kettle(filled=true))
beansResult = beans.getOrElse(throw new Exception("Beans result
errored. "))
waterResult = hotWater.getOrElse(throw new Exception("Water result
errored. "))
result <- makingCoffee(beansResult, waterResult)
} yield Option(result)
coffeeFut.onSuccess {
case Some(s) => println(s"SUCCESS: $s")
case None => println("No coffee found?")
}
coffeeFut.onFailure {
case x => println(s"FAIL: $x")
}
Without Monad transformers, failure scenario
Without Monad transformers, failure scenario
coffeeFut:
scala.concurrent.Future[Option[Coffee]] =
scala.concurrent.impl.Promise
$DefaultPromise@17ee3bd8
scala> FAIL: java.lang.Exception: Beans
result errored.
val coffeeFutT = for {
beans <- OptionT(grindFreshBeans(Beans(fresh=false)))
hotWater <- OptionT(getHotWater(Kettle(filled=true)))
result <- OptionT.liftF(makingCoffee(beans,
hotWater))
} yield result
coffeeFutT.value.onSuccess {
case Some(s) => println(s"SUCCESS: $s")
case None => println("No coffee found?")
}
coffeeFutT.value.onFailure {
case x => println(s"FAIL: $x")
}
With Monad transformers, failure scenario
With Monad transformers, failure scenario
coffeeFutT:
cats.data.OptionT[scala.concurrent.Future
,Coffee] =
OptionT(scala.concurrent.impl.Promise
$DefaultPromise@4e115bbc)
scala> No coffee found?
val coffeeFutT = for {
beans <- OptionT(grindFreshBeans(Beans(fresh=true)))
hotWater <- OptionT(getHotWater(Kettle(filled=true),
clumsy=true))
result <- OptionT.liftF(makingCoffee(beans,
hotWater))
} yield s"$result"
coffeeFutT.value.onSuccess {
case Some(s) => println(s"SUCCESS: $s")
case None => println("No coffee found?")
}
coffeeFutT.value.onFailure {
case x => println(s"FAIL: $x")
}
With monad transformers, failure scenario with
exception
FAIL: $line86.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw
$HotWaterException: Ouch spilled that water!
coffeeFutT:
cats.data.OptionT[scala.concurrent.Future,Coffee] =
OptionT(scala.concurrent.impl.Promise
$DefaultPromise@20e4013)
With monad transformers, failure scenario with
exception
flatMap
• Use monad transformers to short circuit your monads
What did we learn?
• Instead of unwrapping layers of monads, monad
transformers results in a new monad to flatMap with
• Reduce layers of x.map( y => y.map ( ... )) to just
x.map ( y => ...))
x.map ( y => y.map ( ... ) ) map
OptionT
What’s next?
• Many other types of monad transformers: ReaderT,
WriterT, EitherT, StateT
• Since monad transformers give you a monad as a
result-- you can stack them too!
Thank you
Connie Chen - @coni
Twilio
We’re hiring!
final case class OptionT[F[_], A](value: F[Option[A]]) {
def fold[B](default: => B)(f: A => B)(implicit F:
Functor[F]): F[B] =
F.map(value)(_.fold(default)(f))
def map[B](f: A => B)(implicit F: Functor[F]):
OptionT[F, B] =
OptionT(F.map(value)(_.map(f)))
def flatMapF[B](f: A => F[Option[B]])(implicit F:
Monad[F]): OptionT[F, B] =
OptionT(F.flatMap(value)(_.fold(F.pure[Option[B]]
(None))(f)))
OptionT implementation
def liftF[F[_], A](fa: F[A])(implicit F:
Functor[F]): OptionT[F, A] = OptionT(F.map(fa)
(Some(_)))
OptionT implementation

More Related Content

Viewers also liked

Scala Warrior and type-safe front-end development with Scala.js
Scala Warrior and type-safe front-end development with Scala.jsScala Warrior and type-safe front-end development with Scala.js
Scala Warrior and type-safe front-end development with Scala.jstakezoe
 
「ハイレベルメンバーを共創させたら何が起きるか?実験」結果報告会 スライド
「ハイレベルメンバーを共創させたら何が起きるか?実験」結果報告会 スライド「ハイレベルメンバーを共創させたら何が起きるか?実験」結果報告会 スライド
「ハイレベルメンバーを共創させたら何が起きるか?実験」結果報告会 スライドKeita Takizawa
 
Akka-chan's Survival Guide for the Streaming World
Akka-chan's Survival Guide for the Streaming WorldAkka-chan's Survival Guide for the Streaming World
Akka-chan's Survival Guide for the Streaming WorldKonrad Malawski
 
Deadly Code! (seriously) Blocking &amp; Hyper Context Switching Pattern
Deadly Code! (seriously) Blocking &amp; Hyper Context Switching PatternDeadly Code! (seriously) Blocking &amp; Hyper Context Switching Pattern
Deadly Code! (seriously) Blocking &amp; Hyper Context Switching Patternchibochibo
 
Van laarhoven lens
Van laarhoven lensVan laarhoven lens
Van laarhoven lensNaoki Aoyama
 
アクセシビリティはじめました
アクセシビリティはじめましたアクセシビリティはじめました
アクセシビリティはじめましたYuichi Sugiyama
 
BCU30 - Webでできるマルチメディア表現
BCU30 - Webでできるマルチメディア表現BCU30 - Webでできるマルチメディア表現
BCU30 - Webでできるマルチメディア表現Leonardo Ken Orihara
 
Going bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data typesGoing bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data typesPawel Szulc
 
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigiReact Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigiYukiya Nakagawa
 
DevOpsとか言う前にAWSエンジニアに知ってほしいアプリケーションのこと
DevOpsとか言う前にAWSエンジニアに知ってほしいアプリケーションのことDevOpsとか言う前にAWSエンジニアに知ってほしいアプリケーションのこと
DevOpsとか言う前にAWSエンジニアに知ってほしいアプリケーションのことTerui Masashi
 
Akka Cluster and Auto-scaling
Akka Cluster and Auto-scalingAkka Cluster and Auto-scaling
Akka Cluster and Auto-scalingIkuo Matsumura
 
今から始める Lens/Prism
今から始める Lens/Prism今から始める Lens/Prism
今から始める Lens/PrismNaoki Aoyama
 
AWSでアプリ開発するなら 知っておくべこと
AWSでアプリ開発するなら 知っておくべことAWSでアプリ開発するなら 知っておくべこと
AWSでアプリ開発するなら 知っておくべことKeisuke Nishitani
 
Big Data Analytics Tokyo
Big Data Analytics TokyoBig Data Analytics Tokyo
Big Data Analytics TokyoAdam Gibson
 
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)Eugene Yokota
 
バッチを Akka Streams で再実装したら100倍速くなった話 #ScalaMatsuri
バッチを Akka Streams で再実装したら100倍速くなった話 #ScalaMatsuriバッチを Akka Streams で再実装したら100倍速くなった話 #ScalaMatsuri
バッチを Akka Streams で再実装したら100倍速くなった話 #ScalaMatsuriKazuki Negoro
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)x1 ichi
 
Reactive integrations with Akka Streams
Reactive integrations with Akka StreamsReactive integrations with Akka Streams
Reactive integrations with Akka StreamsKonrad Malawski
 

Viewers also liked (20)

Scala Warrior and type-safe front-end development with Scala.js
Scala Warrior and type-safe front-end development with Scala.jsScala Warrior and type-safe front-end development with Scala.js
Scala Warrior and type-safe front-end development with Scala.js
 
「ハイレベルメンバーを共創させたら何が起きるか?実験」結果報告会 スライド
「ハイレベルメンバーを共創させたら何が起きるか?実験」結果報告会 スライド「ハイレベルメンバーを共創させたら何が起きるか?実験」結果報告会 スライド
「ハイレベルメンバーを共創させたら何が起きるか?実験」結果報告会 スライド
 
Akka-chan's Survival Guide for the Streaming World
Akka-chan's Survival Guide for the Streaming WorldAkka-chan's Survival Guide for the Streaming World
Akka-chan's Survival Guide for the Streaming World
 
Deadly Code! (seriously) Blocking &amp; Hyper Context Switching Pattern
Deadly Code! (seriously) Blocking &amp; Hyper Context Switching PatternDeadly Code! (seriously) Blocking &amp; Hyper Context Switching Pattern
Deadly Code! (seriously) Blocking &amp; Hyper Context Switching Pattern
 
Van laarhoven lens
Van laarhoven lensVan laarhoven lens
Van laarhoven lens
 
アクセシビリティはじめました
アクセシビリティはじめましたアクセシビリティはじめました
アクセシビリティはじめました
 
BCU30 - Webでできるマルチメディア表現
BCU30 - Webでできるマルチメディア表現BCU30 - Webでできるマルチメディア表現
BCU30 - Webでできるマルチメディア表現
 
Scala Matsuri 2017
Scala Matsuri 2017Scala Matsuri 2017
Scala Matsuri 2017
 
Pratical eff
Pratical effPratical eff
Pratical eff
 
Going bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data typesGoing bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data types
 
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigiReact Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
 
DevOpsとか言う前にAWSエンジニアに知ってほしいアプリケーションのこと
DevOpsとか言う前にAWSエンジニアに知ってほしいアプリケーションのことDevOpsとか言う前にAWSエンジニアに知ってほしいアプリケーションのこと
DevOpsとか言う前にAWSエンジニアに知ってほしいアプリケーションのこと
 
Akka Cluster and Auto-scaling
Akka Cluster and Auto-scalingAkka Cluster and Auto-scaling
Akka Cluster and Auto-scaling
 
今から始める Lens/Prism
今から始める Lens/Prism今から始める Lens/Prism
今から始める Lens/Prism
 
AWSでアプリ開発するなら 知っておくべこと
AWSでアプリ開発するなら 知っておくべことAWSでアプリ開発するなら 知っておくべこと
AWSでアプリ開発するなら 知っておくべこと
 
Big Data Analytics Tokyo
Big Data Analytics TokyoBig Data Analytics Tokyo
Big Data Analytics Tokyo
 
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
 
バッチを Akka Streams で再実装したら100倍速くなった話 #ScalaMatsuri
バッチを Akka Streams で再実装したら100倍速くなった話 #ScalaMatsuriバッチを Akka Streams で再実装したら100倍速くなった話 #ScalaMatsuri
バッチを Akka Streams で再実装したら100倍速くなった話 #ScalaMatsuri
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)
 
Reactive integrations with Akka Streams
Reactive integrations with Akka StreamsReactive integrations with Akka Streams
Reactive integrations with Akka Streams
 

Similar to Reducing Boilerplate and Combining Effects: A Monad Transformer Example

Joe Bew - Apprendi un nuovo linguaggio sfruttando il TDD e il Clean Code - Co...
Joe Bew - Apprendi un nuovo linguaggio sfruttando il TDD e il Clean Code - Co...Joe Bew - Apprendi un nuovo linguaggio sfruttando il TDD e il Clean Code - Co...
Joe Bew - Apprendi un nuovo linguaggio sfruttando il TDD e il Clean Code - Co...Codemotion
 
For this homework, you will develop a class called VendingMachine th.pdf
For this homework, you will develop a class called VendingMachine th.pdfFor this homework, you will develop a class called VendingMachine th.pdf
For this homework, you will develop a class called VendingMachine th.pdfinfo309708
 
Damn Fine CoffeeScript
Damn Fine CoffeeScriptDamn Fine CoffeeScript
Damn Fine CoffeeScriptniklal
 
Getting property based testing to work after struggling for 3 years
Getting property based testing to work after struggling for 3 yearsGetting property based testing to work after struggling for 3 years
Getting property based testing to work after struggling for 3 yearsSaurabh Nanda
 
Coffeescript - take a sip of code
Coffeescript - take a sip of codeCoffeescript - take a sip of code
Coffeescript - take a sip of codeDimitris Tsironis
 
Php tour 2018 un autre regard sur la validation (1)
Php tour 2018   un autre regard sur la validation (1)Php tour 2018   un autre regard sur la validation (1)
Php tour 2018 un autre regard sur la validation (1)Quentin Pautrat
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreNicolas Carlo
 

Similar to Reducing Boilerplate and Combining Effects: A Monad Transformer Example (11)

Coffeescript slides
Coffeescript slidesCoffeescript slides
Coffeescript slides
 
test
testtest
test
 
Joe Bew - Apprendi un nuovo linguaggio sfruttando il TDD e il Clean Code - Co...
Joe Bew - Apprendi un nuovo linguaggio sfruttando il TDD e il Clean Code - Co...Joe Bew - Apprendi un nuovo linguaggio sfruttando il TDD e il Clean Code - Co...
Joe Bew - Apprendi un nuovo linguaggio sfruttando il TDD e il Clean Code - Co...
 
Camel vs Spring EIP JAVA DSL
Camel vs Spring EIP JAVA DSLCamel vs Spring EIP JAVA DSL
Camel vs Spring EIP JAVA DSL
 
For this homework, you will develop a class called VendingMachine th.pdf
For this homework, you will develop a class called VendingMachine th.pdfFor this homework, you will develop a class called VendingMachine th.pdf
For this homework, you will develop a class called VendingMachine th.pdf
 
Damn Fine CoffeeScript
Damn Fine CoffeeScriptDamn Fine CoffeeScript
Damn Fine CoffeeScript
 
Getting property based testing to work after struggling for 3 years
Getting property based testing to work after struggling for 3 yearsGetting property based testing to work after struggling for 3 years
Getting property based testing to work after struggling for 3 years
 
Coffeescript - take a sip of code
Coffeescript - take a sip of codeCoffeescript - take a sip of code
Coffeescript - take a sip of code
 
Php tour 2018 un autre regard sur la validation (1)
Php tour 2018   un autre regard sur la validation (1)Php tour 2018   un autre regard sur la validation (1)
Php tour 2018 un autre regard sur la validation (1)
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscore
 
Quick coffeescript
Quick coffeescriptQuick coffeescript
Quick coffeescript
 

Recently uploaded

What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesVictoriaMetrics
 
Data modeling 101 - Basics - Software Domain
Data modeling 101 - Basics - Software DomainData modeling 101 - Basics - Software Domain
Data modeling 101 - Basics - Software DomainAbdul Ahad
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxRTS corp
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Rob Geurden
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITmanoharjgpsolutions
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...Bert Jan Schrijver
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingShane Coughlan
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfmaor17
 
Effectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorEffectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorTier1 app
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogueitservices996
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics
 
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesAmazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesKrzysztofKkol1
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxAndreas Kunz
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...OnePlan Solutions
 
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonApplitools
 
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdfAndrey Devyatkin
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecturerahul_net
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLionel Briand
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jNeo4j
 
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfRTS corp
 

Recently uploaded (20)

What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 Updates
 
Data modeling 101 - Basics - Software Domain
Data modeling 101 - Basics - Software DomainData modeling 101 - Basics - Software Domain
Data modeling 101 - Basics - Software Domain
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh IT
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdf
 
Effectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorEffectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryError
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogue
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
 
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesAmazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
 
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
 
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecture
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and Repair
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
 
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
 

Reducing Boilerplate and Combining Effects: A Monad Transformer Example

  • 1. Reducing Boilerplate and Combining Effects: A Monad Transformer Example Scala Matsuri - Feb 25th, 2017 Connie Chen :
  • 2. Hello • @coni • Data Platform team @ Twilio • @ http://github.com/conniec
  • 3. • Monad transformers allow different monads to compose • Combine effects of monads to create a SUPER MONAD • Eg. Future[Option], Future[Either], Reader[Option] • In this example, we will use the Cats library... What are Monad transformers?
  • 4. Future[Either[A, B]] turns into EitherT[Future, A, B] Future[Option[A]] turns into OptionT[Future, A]
  • 5. import scala.concurrent.Future import cats.data.OptionT import cats.implicits._ import scala.concurrent.ExecutionContext.Implicits.glo bal case class Beans(fresh: Boolean = true) case class Grounds() class GroundBeansException(s: String) extends Exception(s: String) 1. Example: Making coffee! Step 1. Grind the beans
  • 6. def grindFreshBeans(beans: Beans, clumsy: Boolean = false): Future[Option[Grounds]] = { if (clumsy) { Future.failed(new GroundBeansException("We are bad at grinding")) } else if (beans.fresh) { Future.successful(Option(Grounds())) } else { Future.successful(None) } } 1. Example: Making coffee! Step 1. Grind the beans
  • 7. Step 1. Grind the beans Three different kind of results: • Value found • Value not found • Future failed Future 3 Example: Making coffee!
  • 8. Step 2. Boil hot water case class Kettle(filled: Boolean = true) case class Water() case class Coffee(delicious: Boolean) class HotWaterException(s: String) extends Exception(s: String) 2. def getHotWater(kettle: Kettle, clumsy: Boolean = false): Future[Option[Water]] = { if (clumsy) { Future.failed(new HotWaterException("Ouch spilled that water!")) } else if (kettle.filled) { Future.successful(Option(Water())) } else { Future.successful(None) } }
  • 9. Step 3. Combine water and coffee (it's a pourover) 3. ( ) def makingCoffee(grounds: Grounds, water: Water): Future[Coffee] = { println(s"Making coffee with... $grounds and $water") Future.successful(Coffee(delicious=true)) }
  • 10. val coffeeFut = for { } yield Option(result) coffeeFut.onSuccess { case Some(s) => println(s"SUCCESS: $s") case None => println("No coffee found?") } coffeeFut.onFailure { case x => println(s"FAIL: $x") } Without Monad transformers, success scenario beans <- grindFreshBeans(Beans(fresh=true)) hotWater <- getHotWater(Kettle(filled=true)) beansResult = beans.getOrElse(throw new Exception("Beans result errored. ")) waterResult = hotWater.getOrElse(throw new Exception("Water result errored. ")) result <- makingCoffee(beansResult, waterResult)
  • 11. Without Monad transformers, success scenario coffeeFut: scala.concurrent.Future[Option[Coffee]] = scala.concurrent.impl.Promise $DefaultPromise@7404ac2 scala> Making coffee with... Grounds() and Water() SUCCESS: Coffee(true)
  • 12. With Monad transformers, success scenario val coffeeFutMonadT = for { beans <- OptionT(grindFreshBeans(Beans(fresh=true))) hotWater <- OptionT(getHotWater(Kettle(filled=true))) result <- OptionT.liftF(makingCoffee(beans, hotWater)) } yield result coffeeFutMonadT.value.onSuccess { case Some(s) => println(s"SUCCESS: $s") case None => println("No coffee found?") } coffeeFutMonadT.value.onFailure { case x => println(s"FAIL: $x") }
  • 13. coffeeFutMonadT: cats.data.OptionT[scala.concurrent.Future, Coffee] = OptionT(scala.concurrent.impl.Promise $DefaultPromise@4a1c4b40) scala> Making coffee with... Grounds() and Water() SUCCESS: Coffee(true) With Monad transformers, success scenario
  • 14. OptionT `fromOption` gives you an OptionT from Option Internally, it is wrapping your option in a Future.successful() `liftF` gives you an OptionT from Future Internally, it is mapping on your Future and wrapping it in a Some() Helper functions on OptionT
  • 15. val coffeeFut = for { beans <- grindFreshBeans(Beans(fresh=false)) hotWater <- getHotWater(Kettle(filled=true)) beansResult = beans.getOrElse(throw new Exception("Beans result errored. ")) waterResult = hotWater.getOrElse(throw new Exception("Water result errored. ")) result <- makingCoffee(beansResult, waterResult) } yield Option(result) coffeeFut.onSuccess { case Some(s) => println(s"SUCCESS: $s") case None => println("No coffee found?") } coffeeFut.onFailure { case x => println(s"FAIL: $x") } Without Monad transformers, failure scenario
  • 16. Without Monad transformers, failure scenario coffeeFut: scala.concurrent.Future[Option[Coffee]] = scala.concurrent.impl.Promise $DefaultPromise@17ee3bd8 scala> FAIL: java.lang.Exception: Beans result errored.
  • 17. val coffeeFutT = for { beans <- OptionT(grindFreshBeans(Beans(fresh=false))) hotWater <- OptionT(getHotWater(Kettle(filled=true))) result <- OptionT.liftF(makingCoffee(beans, hotWater)) } yield result coffeeFutT.value.onSuccess { case Some(s) => println(s"SUCCESS: $s") case None => println("No coffee found?") } coffeeFutT.value.onFailure { case x => println(s"FAIL: $x") } With Monad transformers, failure scenario
  • 18. With Monad transformers, failure scenario coffeeFutT: cats.data.OptionT[scala.concurrent.Future ,Coffee] = OptionT(scala.concurrent.impl.Promise $DefaultPromise@4e115bbc) scala> No coffee found?
  • 19. val coffeeFutT = for { beans <- OptionT(grindFreshBeans(Beans(fresh=true))) hotWater <- OptionT(getHotWater(Kettle(filled=true), clumsy=true)) result <- OptionT.liftF(makingCoffee(beans, hotWater)) } yield s"$result" coffeeFutT.value.onSuccess { case Some(s) => println(s"SUCCESS: $s") case None => println("No coffee found?") } coffeeFutT.value.onFailure { case x => println(s"FAIL: $x") } With monad transformers, failure scenario with exception
  • 20. FAIL: $line86.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw $HotWaterException: Ouch spilled that water! coffeeFutT: cats.data.OptionT[scala.concurrent.Future,Coffee] = OptionT(scala.concurrent.impl.Promise $DefaultPromise@20e4013) With monad transformers, failure scenario with exception
  • 21. flatMap • Use monad transformers to short circuit your monads What did we learn? • Instead of unwrapping layers of monads, monad transformers results in a new monad to flatMap with • Reduce layers of x.map( y => y.map ( ... )) to just x.map ( y => ...)) x.map ( y => y.map ( ... ) ) map
  • 22. OptionT What’s next? • Many other types of monad transformers: ReaderT, WriterT, EitherT, StateT • Since monad transformers give you a monad as a result-- you can stack them too!
  • 23. Thank you Connie Chen - @coni Twilio We’re hiring!
  • 24. final case class OptionT[F[_], A](value: F[Option[A]]) { def fold[B](default: => B)(f: A => B)(implicit F: Functor[F]): F[B] = F.map(value)(_.fold(default)(f)) def map[B](f: A => B)(implicit F: Functor[F]): OptionT[F, B] = OptionT(F.map(value)(_.map(f))) def flatMapF[B](f: A => F[Option[B]])(implicit F: Monad[F]): OptionT[F, B] = OptionT(F.flatMap(value)(_.fold(F.pure[Option[B]] (None))(f))) OptionT implementation
  • 25. def liftF[F[_], A](fa: F[A])(implicit F: Functor[F]): OptionT[F, A] = OptionT(F.map(fa) (Some(_))) OptionT implementation