SlideShare une entreprise Scribd logo
1  sur  43
Télécharger pour lire hors ligne
Monads
An introduction to the brave new world
…or the old one?
Mikhail Girkin
Software engineer, Wonga.com
About me
 About 8 years of development experience
 PhD in engineering
 About 4 years worked as university professor
 Mainly C# developer, mainly back-end
 Interested in functional and hybrid languages
 Doing Scala in evening-projects
Agenda
 C# devs, Java 8 devs already use monads, they just don’t know about it
 A simple definition of monad
 Scala for-comprehension and monads
 Monads for everyday usage
 Seq
 Option (Maybe)
 Try
 Future
 Random distrubution monad
 An example of “could-be-real” code
 Q&A
You’ve already used it
case class Flight(code: String, …)
case class Airport(
outboundFlights: Seq[Flight],
inboundFlights: Seq[Flight],
…
)
case class City(
airports: Seq[Airport],
…
)
You’ve already used it
We have a set of cities as an input, and want to get all the outbound
flight codes from them:
def outboundFlights(cities: Seq[City]): Seq[String] =
cities.flatMap(c => c.airports)
.flatMap(airp => airp.outboundFlights)
.map(flight => flight.code)
… and even in C# or Java
Cities
.SelectMany(c => c.Airports)
.SelectMany(a => a.OutboundFlights)
.Select(f => f.FlightCode)
cities
.flatMap(c -> c.getAirports().stream())
.flatMap(a -> a.getOutboundFlights().stream())
.map(f -> f.getFlightCode())
.collect(…)
If you don’t know about flatMap
 Collection API from functional world
 Easy and expressive way to deal with collections
 Map
 map[T, TOut](Seq[T], T => TOut): Seq[TOut]
 Seq[T] => (T => TOut) => Seq[TOut]
 Seq(1, 2, 3, 4).map(x => x+1) == Seq(2, 3, 4, 5)
 flatMap
 flatMap[T, TOut](Seq[T], T => Seq[TOut]): Seq[TOut]
 Seq[T] => (T => Seq[TOut] => Seq[TOut]
 Seq(1, 2, 3, 4).flatMap(x => Seq(x, x+1)) == Seq(1, 2, 2, 3, 3, 4, 4, 5)
An unexpected move
def outboundFlights(cities: Seq[City]): Seq[String] =
cities
.flatMap(c => c.airports
.flatMap(airp => airp.outboundFlights
.map(flight => flight.code)
)
)
Bulky and cumbersome?
An unexpected move towards for
def outboundFlights(cities: Seq[City]): Seq[String] =
for {
city <- cities
airport <- city.airports
flight <- airport.outboundFlights
} yield flight.code
A little bit more for comprehensions
//Outbound flights from international airports
def outInternationalFlights(cities: Seq[City]): Seq[String] =
for {
city <- cities
airport <- city.airports if airport.isInternational
flight <- airport.outboundFlights
} yield flight.code
withFilter!
withFilter: Seq[T] => (T => Boolean) => Seq[T]
def outboundFlights(cities: Seq[City]): Seq[String] =
cities
.flatMap(c =>
c.airports
.withFilter(a => a.isInternational)
.flatMap(airp => airp.outboundFlights.map(
flight => flight.code
))
)
A magic of flatMap
1. cities.flatMap(c => c.airports)
2. flatMap(cities, c => airports)
3. flatMap(Seq[City], City => Seq[Airports]): Seq[Airports]
4. flatMap[A, B](Seq[A], A => Seq[B]): Seq[B]
5. Seq[A] => (A => Seq[B]) => Seq[B]
And some magic:
M[A] => (A => M[B]) => M[B]
Welcome the monad!
 Nothing more then a design pattern
 Consist of 3 main parts:
 Type: A
 Unit (construction) operation: A => M[A]
 Bind (SelectMany, flatMap) operation: M[A] => (A => M[B]) => M[B]
 Other common operations:
 Map: M[A] => (A => B) => M[B]
 Lift: (A => B) => (M[A] => M[B])
 Encapsulates some computation with the defined rules
 Seq is a monad. Rules of computation – apply the given function to each of the value,
combine the results in a Seq
Or some other definitions
1. Monads are return types that guide you through the happy path.
(Erik Meijer)
2. Monads are parametric types with two operations flatMap and unit
that obey some algebraic laws. (Martin Odersky)
3. Monads are structures that represent computations defined as
sequences of steps. (Wikipedia)
4. Monads are chainable container types that trap values or
computations and allow them to be transformed in confinement.
(@mttkay)
Laws of monads
Let’s say unit(x) – monad constructor, m – monad object, f – function A => M[A]
1. unit(x).flatMap(f) == f(x)
2. m.flatMap(x => unit(x)) == m
3. m.flatMap(f).flatMap(g) == m.flatMap(x => f(x).flatMap(g))
Forget about laws, let mathematicians earn their money, let’s do something usefull!
Maybe?
Let’s imagine Java-style (C#-style) programming in Scala
def getPaymentCardId(accountId: UUID): UUID = {
val account = accountDao.get(accountId)
if(account == null) return null
if(account.paymentCard == null) return null
return account.paymentCard.paymentCardId
}
Maybe… Option!
trait Option[T] {
def flatMap[TOut](f: T => Option[TOut]): Option[TOut]
def map[TOut](f: T => TOut): Option[TOut]
}
case class Some[T] (value: T) extends Option[T] {
def flatMap[TOut](f: T => Option[TOut]) = f(value)
def map[TOut](f: T => TOut): Option[TOut] = ??? /* Exercise! */
}
case object None extends Option[Nothing] {
def flatMap[T, TOut](f: T => Option[TOut]) = None
def map[TOut](f: T => TOut): Option[TOut] = ??? /* Exercise! */
}
Maybe!
def getPaymentCardId(accountId: UUID) =
accountDao.get(accountId)
.flatMap(acc => acc.paymentCard)
.map(card => card.paymentCardId)
def getPaymentCardId(accountId: UUID) =
for {
account <- accountDao.get(accountId)
card <- account.paymentCard
} yield card.paymentCardId
Or even maybe... remember flatMap!
val firstNameOpt: Option[String]
val lastNameOpt: Option[String]
case class Person(
firstName: String,
lastName: String
)
for {
firstName <- firstNameOpt
lastName <- lastNameOpt
} yield Person(firstName, lastName)
What do we get?
 Code is readable
 Concentration on happy path, non-happy path is delegated to
monad
 Code is maintainable
 Less errors
 No NullReferenceException! Never!
 Using for-loops for monads is mind-blowing feature for a
developer with an imperative background
 But once you get used to it…
Exceptions, exceptions, exceptions…
Every Java or C# developer sometimes ends up with something like this:
try
{
SomeType value = connection.getSomething()
return connection.getAnotherSomething(value)
}
catch (Exception exc)
{
// do other stuff
}
It is bulky and cumbersome, as well as time-consuming for stack rewind
Exceptions… try, not catch!
trait Try[T]
case class Success[T](value: T) extends Try[T]
trait Failure extends Try[Nothing]
case class NotFound(exc: NotFoundException) extends Failure
case class NotAuthorized(exc: SecurityException) extends Failure
…
flatMap and map are easy to implement!
flatMap for Try
Start with the type: Try[T] => (T => Try[TOut]) => Try[TOut]
def flatMap[T, TOut](in: Try[T], action: T => Try[TOut]): Try[TOut] = {
in match {
case Success(value) => action(value)
case _ => in
}
}
Try is a monad!
Try!
val result = for {
value <- connection.getSomething()
otherValue <- connection.getAnotherSomething(value)
} yield otherValue
result match {
case Success(value) => …
case NotFound => …
case NotAuthorized => …
}
 Returns Try[T]
 Type of value explicitly says that the client should deal with exceptions
 The code is clean as concise
 Exceptions is not an only case for Try-Failure monad. The monad called “Error” in generic case, example is
coming
Asynchronously blowing up mind
 Writing async code is another level of complexity
 In pure C# 2 (I suppose Java too) async code often ended up with
spaghetti-like code
 We are going to live in a non-blocking world
Bright future
 A Future is an object holding a value which may become available at
some point.
 Resolves in two possible ways
 When a Future is completed with a value, we say that the future was
successfully completed with that value.
 When there has been an error, we say that the future completed with failure
What is the difference with Error monad? Async!
So someone will care about async!
The magic of Future
price: Future[Money] = nasdaq.getSharePrice(“AAPL”)
Is value there? – Don’t know
Could we do something with it? – Why not?
price.map(p => costOfOurStock(p)) //returns Future
price.flatMap(
p => nasdaq.bid(“AAPL”, p-0.01, 10)) //Future on Future
Future
 Will not go deep into Promises-Futures
 Future is a good example, where flatMap shines
 flatMap abstracts everything from the developer except the
operations on values
 Concentration on happy path at the most extent
Random distribution monad
A value inside a monad is some random value of type T distributed according to some law
A good an uncommon example of monad application
trait Distribution[T] {
def sample(): T
def flatMap[TOut](f: T => Distribution[TOut]): Distribution[TOut]
def map[TOut](f: T => TOut): Distribution[TOut]
}
Each time sample is called new random value is generated
Source: https://github.com/mikegirkin/randommonad
Implementation
trait Distribution[T] {
self =>
def sample(): T
def flatMap[TOut](f: T => Distribution[TOut]): Distribution[TOut] = {
new Distribution[TOut] {
override def sample = f(self.sample()).sample()
}
}
def map[TOut](f: T => TOut): Distribution[TOut] = {
new Distribution[TOut] {
override def sample = f(self.sample())
}
}
}
A first real implementation
A uniform distribution of discrete random values from the given alphabet
def uniform[T](values: Array[T]): Distribution[T] = new Distribution[T] {
override def sample: T = {
val index = rnd.nextInt(values.size)
values(index)
}
}
Extracting distribution
Results in sequence of (value, probability)
def histo: Seq[(T, Double)] = {
val n = 1000000
val map = scala.collection.mutable.Map[T, Double]()
for(i <- 1 to n) {
val s = sample()
if(map.isDefinedAt(s)) map(s) = map(s) + 1.0/n
else map(s) = 1.0/n
}
map.toSeq
}
What could we do?
Ever played D&D game?
def dice(sides: Int) =
Distribution.uniform(Range(1, sides+1, 1))
val d6 = dice(6)
val d20 = dice(20)
val d3d6 = for {
x <- d6
y <- d6
z <- d6
} yield x+y+z
18: 0.0046
17: 0.0139
16: 0.0278
15: 0.0464
14: 0.0692
13: 0.0972
12: 0.1156
11: 0.1251
10: 0.1255
9: 0.1161
8: 0.0970
7: 0.0694
6: 0.0463
5: 0.0274
4: 0.0140
3: 0.0047
Drivers and accidents
Say we have a crossroads with the yellow traffic lights at the moment,
and to drivers approaching from the orthogonal directions.
Drivers:
0.2 – aggressive, will accelerate with probability 0.9
0.6 – normal, will accelerate with probability 0.2
0.2 – cautious, will accelerate with probability 0.1
Let’s use the random monad
Given distribution
def given[T](probs: Seq[(Double, T)]): Distribution[T] =
new Distribution[T] {
//result in i.e. ((0.2 -> cautious), (0.8 -> normal), (1.0 -> aggressive))
val aggrProbs = probs
.scanLeft(0.0)((p, x) => p + x._1)
.drop(1)
.zip(probs.map(_._2))
override def sample: T = {
val r = rnd.nextDouble()
aggrProbs.find(x => x._1 >= r).get._2
}
}
Keep code simple
def aggressive = Distribution.given(Seq((0.9 -> true), (0.1 -> false)))
def normal = Distribution.given(Seq((0.2 -> true), (0.8 -> false)))
def cautious = Distribution.given(Seq((0.1 -> true), (0.9 -> false)))
def driver = Distribution.given(Seq(
(0.2 -> cautious), (0.6 -> normal), (0.2 -> aggressive)
))
val collision = for {
d1 <- driver
d2 <- driver
act1 <- d1
act2 <- d2
} yield act1 && act2
Results in:
false: 0.8976
true: 0.1024
A real code (still simplified) example
Let’s say we want to implement user updating the ticket in the ticket-tracking
system
A usecase (happy path): user fills the form with the updated values, and
presses “Update”. The system updates the ticket in the storage, and redirects
to the ticket information page, and then sends the email notification.
What can go wrong?
 Invalid values submitted
 There is no ticket to update
 The user is not allowed update that ticket
 The db could fail to perform the update
Monad!
Error monad is what we want!
trait MyAppResult[T]
case class MyAppSuccess[T](result: T) extends MyAppResult[T]
trait MyAppFailure extends MyAppResult[Nothing]
case class InvalidInput(
errors: Seq[InputError]) extends MyAppFailure
case object TicketNotFound extends MyAppFailure
case object NoPermission extends MyAppFailure
case object DbFailure extends MyAppFailure
The code sketch
val form = getUserInput()
for {
validatedInput <- validateForm(form)
ticket <- retreiveTicket(validatedInput.ticketId)
_ <- check(currentUser.canEditTicket(ticket))
updatedTicket <- updateTicket(ticket, validatedInput)
_ <- saveTicket(updatedTicket)
} yield updatedTicket
updatedTicket match {
case MyAppSuccess(ticket) => ...
case InvalidInput(errors) => ...
case TicketNotFound => ...
...
}
Recap: Monadic pattern
1. Get initial value enclosed in monad
2. Do something with the value enclosed, get monad
3. Do something with the value enclosed, get monad
4. …
5. PROFIT!!! Result resolution
Recap
 Monads is the way to execute some computation following the
common rules
 Monads is all about flatMap, nothing more
 Monads is the way to abstract common rules and reuse them
 It is not a rocket science, and you’ve already used them
 Monads for everyday use:
 Seq
 Option
 Try/Error
 Future
Some links
 Erik Meijer - Contravariance is the Dual of Covariance
(http://www.infoq.com/interviews/meijer-monads)
 Principles of reactive programming
(https://www.coursera.org/course/reactive)
 Robert Martin - Monads within Clojure
(https://www.youtube.com/watch?v=Usxf3aLimtU)
 Dick Wall - What Have The Monads Ever Done For Us
(https://www.youtube.com/watch?v=2IYNPUp751g)
Q&A
Thank you!

Contenu connexe

Tendances

Function recap
Function recapFunction recap
Function recap
alish sha
 

Tendances (20)

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
 
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'
 
Revision1schema C programming
Revision1schema C programmingRevision1schema C programming
Revision1schema C programming
 
Chapter 5 exercises Balagurusamy Programming ANSI in c
Chapter 5 exercises Balagurusamy Programming ANSI  in cChapter 5 exercises Balagurusamy Programming ANSI  in c
Chapter 5 exercises Balagurusamy Programming ANSI in c
 
Revision1 C programming
Revision1 C programmingRevision1 C programming
Revision1 C programming
 
Lab. Programs in C
Lab. Programs in CLab. Programs in C
Lab. Programs in C
 
Functor Laws
Functor LawsFunctor Laws
Functor Laws
 
7. input and output functions
7. input and output functions7. input and output functions
7. input and output functions
 
Chapter 3 : Balagurusamy Programming ANSI in C
Chapter 3 : Balagurusamy Programming ANSI in C Chapter 3 : Balagurusamy Programming ANSI in C
Chapter 3 : Balagurusamy Programming ANSI in C
 
The solution manual of c by robin
The solution manual of c by robinThe solution manual of c by robin
The solution manual of c by robin
 
USE OF PRINT IN PYTHON PART 2
USE OF PRINT IN PYTHON PART 2USE OF PRINT IN PYTHON PART 2
USE OF PRINT IN PYTHON PART 2
 
Computer programming subject notes. Quick easy notes for C Programming.Cheat ...
Computer programming subject notes. Quick easy notes for C Programming.Cheat ...Computer programming subject notes. Quick easy notes for C Programming.Cheat ...
Computer programming subject notes. Quick easy notes for C Programming.Cheat ...
 
Monad Fact #2
Monad Fact #2Monad Fact #2
Monad Fact #2
 
Monad Transformers - Part 1
Monad Transformers - Part 1Monad Transformers - Part 1
Monad Transformers - Part 1
 
Arrays
ArraysArrays
Arrays
 
Function recap
Function recapFunction recap
Function recap
 
SPL 6.1 | Advanced problems on Operators and Math.h function in C
SPL 6.1 | Advanced problems on Operators and Math.h function in CSPL 6.1 | Advanced problems on Operators and Math.h function in C
SPL 6.1 | Advanced problems on Operators and Math.h function in C
 
Arrays
ArraysArrays
Arrays
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adts
 
Core programming in c
Core programming in cCore programming in c
Core programming in c
 

Similaire à Monads - Dublin Scala meetup

Function recap
Function recapFunction recap
Function recap
alish sha
 
Pointcuts and Analysis
Pointcuts and AnalysisPointcuts and Analysis
Pointcuts and Analysis
Wiwat Ruengmee
 
yield and return (poor English ver)
yield and return (poor English ver)yield and return (poor English ver)
yield and return (poor English ver)
bleis tift
 

Similaire à Monads - Dublin Scala meetup (20)

C++11 - A Change in Style - v2.0
C++11 - A Change in Style - v2.0C++11 - A Change in Style - v2.0
C++11 - A Change in Style - v2.0
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
 
Go Programming Language (Golang)
Go Programming Language (Golang)Go Programming Language (Golang)
Go Programming Language (Golang)
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and Effects
 
functions
functionsfunctions
functions
 
The what over the how (another way on android development with kotlin)
The what over the how (another way on android development with kotlin)The what over the how (another way on android development with kotlin)
The what over the how (another way on android development with kotlin)
 
talk at Virginia Bioinformatics Institute, December 5, 2013
talk at Virginia Bioinformatics Institute, December 5, 2013talk at Virginia Bioinformatics Institute, December 5, 2013
talk at Virginia Bioinformatics Institute, December 5, 2013
 
Function recap
Function recapFunction recap
Function recap
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
Monadologie
MonadologieMonadologie
Monadologie
 
Golang and Eco-System Introduction / Overview
Golang and Eco-System Introduction / OverviewGolang and Eco-System Introduction / Overview
Golang and Eco-System Introduction / Overview
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg Mürk
 
Pointcuts and Analysis
Pointcuts and AnalysisPointcuts and Analysis
Pointcuts and Analysis
 
yield and return (poor English ver)
yield and return (poor English ver)yield and return (poor English ver)
yield and return (poor English ver)
 
Computer Graphics in Java and Scala - Part 1b
Computer Graphics in Java and Scala - Part 1bComputer Graphics in Java and Scala - Part 1b
Computer Graphics in Java and Scala - Part 1b
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
 
Legacy lambda code
Legacy lambda codeLegacy lambda code
Legacy lambda code
 
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)
 
Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 

Dernier

Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
chiefasafspells
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
masabamasaba
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 

Dernier (20)

%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 

Monads - Dublin Scala meetup

  • 1. Monads An introduction to the brave new world …or the old one? Mikhail Girkin Software engineer, Wonga.com
  • 2. About me  About 8 years of development experience  PhD in engineering  About 4 years worked as university professor  Mainly C# developer, mainly back-end  Interested in functional and hybrid languages  Doing Scala in evening-projects
  • 3. Agenda  C# devs, Java 8 devs already use monads, they just don’t know about it  A simple definition of monad  Scala for-comprehension and monads  Monads for everyday usage  Seq  Option (Maybe)  Try  Future  Random distrubution monad  An example of “could-be-real” code  Q&A
  • 4. You’ve already used it case class Flight(code: String, …) case class Airport( outboundFlights: Seq[Flight], inboundFlights: Seq[Flight], … ) case class City( airports: Seq[Airport], … )
  • 5. You’ve already used it We have a set of cities as an input, and want to get all the outbound flight codes from them: def outboundFlights(cities: Seq[City]): Seq[String] = cities.flatMap(c => c.airports) .flatMap(airp => airp.outboundFlights) .map(flight => flight.code)
  • 6. … and even in C# or Java Cities .SelectMany(c => c.Airports) .SelectMany(a => a.OutboundFlights) .Select(f => f.FlightCode) cities .flatMap(c -> c.getAirports().stream()) .flatMap(a -> a.getOutboundFlights().stream()) .map(f -> f.getFlightCode()) .collect(…)
  • 7. If you don’t know about flatMap  Collection API from functional world  Easy and expressive way to deal with collections  Map  map[T, TOut](Seq[T], T => TOut): Seq[TOut]  Seq[T] => (T => TOut) => Seq[TOut]  Seq(1, 2, 3, 4).map(x => x+1) == Seq(2, 3, 4, 5)  flatMap  flatMap[T, TOut](Seq[T], T => Seq[TOut]): Seq[TOut]  Seq[T] => (T => Seq[TOut] => Seq[TOut]  Seq(1, 2, 3, 4).flatMap(x => Seq(x, x+1)) == Seq(1, 2, 2, 3, 3, 4, 4, 5)
  • 8. An unexpected move def outboundFlights(cities: Seq[City]): Seq[String] = cities .flatMap(c => c.airports .flatMap(airp => airp.outboundFlights .map(flight => flight.code) ) ) Bulky and cumbersome?
  • 9. An unexpected move towards for def outboundFlights(cities: Seq[City]): Seq[String] = for { city <- cities airport <- city.airports flight <- airport.outboundFlights } yield flight.code
  • 10. A little bit more for comprehensions //Outbound flights from international airports def outInternationalFlights(cities: Seq[City]): Seq[String] = for { city <- cities airport <- city.airports if airport.isInternational flight <- airport.outboundFlights } yield flight.code
  • 11. withFilter! withFilter: Seq[T] => (T => Boolean) => Seq[T] def outboundFlights(cities: Seq[City]): Seq[String] = cities .flatMap(c => c.airports .withFilter(a => a.isInternational) .flatMap(airp => airp.outboundFlights.map( flight => flight.code )) )
  • 12. A magic of flatMap 1. cities.flatMap(c => c.airports) 2. flatMap(cities, c => airports) 3. flatMap(Seq[City], City => Seq[Airports]): Seq[Airports] 4. flatMap[A, B](Seq[A], A => Seq[B]): Seq[B] 5. Seq[A] => (A => Seq[B]) => Seq[B] And some magic: M[A] => (A => M[B]) => M[B]
  • 13. Welcome the monad!  Nothing more then a design pattern  Consist of 3 main parts:  Type: A  Unit (construction) operation: A => M[A]  Bind (SelectMany, flatMap) operation: M[A] => (A => M[B]) => M[B]  Other common operations:  Map: M[A] => (A => B) => M[B]  Lift: (A => B) => (M[A] => M[B])  Encapsulates some computation with the defined rules  Seq is a monad. Rules of computation – apply the given function to each of the value, combine the results in a Seq
  • 14. Or some other definitions 1. Monads are return types that guide you through the happy path. (Erik Meijer) 2. Monads are parametric types with two operations flatMap and unit that obey some algebraic laws. (Martin Odersky) 3. Monads are structures that represent computations defined as sequences of steps. (Wikipedia) 4. Monads are chainable container types that trap values or computations and allow them to be transformed in confinement. (@mttkay)
  • 15. Laws of monads Let’s say unit(x) – monad constructor, m – monad object, f – function A => M[A] 1. unit(x).flatMap(f) == f(x) 2. m.flatMap(x => unit(x)) == m 3. m.flatMap(f).flatMap(g) == m.flatMap(x => f(x).flatMap(g)) Forget about laws, let mathematicians earn their money, let’s do something usefull!
  • 16. Maybe? Let’s imagine Java-style (C#-style) programming in Scala def getPaymentCardId(accountId: UUID): UUID = { val account = accountDao.get(accountId) if(account == null) return null if(account.paymentCard == null) return null return account.paymentCard.paymentCardId }
  • 17. Maybe… Option! trait Option[T] { def flatMap[TOut](f: T => Option[TOut]): Option[TOut] def map[TOut](f: T => TOut): Option[TOut] } case class Some[T] (value: T) extends Option[T] { def flatMap[TOut](f: T => Option[TOut]) = f(value) def map[TOut](f: T => TOut): Option[TOut] = ??? /* Exercise! */ } case object None extends Option[Nothing] { def flatMap[T, TOut](f: T => Option[TOut]) = None def map[TOut](f: T => TOut): Option[TOut] = ??? /* Exercise! */ }
  • 18. Maybe! def getPaymentCardId(accountId: UUID) = accountDao.get(accountId) .flatMap(acc => acc.paymentCard) .map(card => card.paymentCardId) def getPaymentCardId(accountId: UUID) = for { account <- accountDao.get(accountId) card <- account.paymentCard } yield card.paymentCardId
  • 19. Or even maybe... remember flatMap! val firstNameOpt: Option[String] val lastNameOpt: Option[String] case class Person( firstName: String, lastName: String ) for { firstName <- firstNameOpt lastName <- lastNameOpt } yield Person(firstName, lastName)
  • 20. What do we get?  Code is readable  Concentration on happy path, non-happy path is delegated to monad  Code is maintainable  Less errors  No NullReferenceException! Never!  Using for-loops for monads is mind-blowing feature for a developer with an imperative background  But once you get used to it…
  • 21. Exceptions, exceptions, exceptions… Every Java or C# developer sometimes ends up with something like this: try { SomeType value = connection.getSomething() return connection.getAnotherSomething(value) } catch (Exception exc) { // do other stuff } It is bulky and cumbersome, as well as time-consuming for stack rewind
  • 22. Exceptions… try, not catch! trait Try[T] case class Success[T](value: T) extends Try[T] trait Failure extends Try[Nothing] case class NotFound(exc: NotFoundException) extends Failure case class NotAuthorized(exc: SecurityException) extends Failure … flatMap and map are easy to implement!
  • 23. flatMap for Try Start with the type: Try[T] => (T => Try[TOut]) => Try[TOut] def flatMap[T, TOut](in: Try[T], action: T => Try[TOut]): Try[TOut] = { in match { case Success(value) => action(value) case _ => in } } Try is a monad!
  • 24. Try! val result = for { value <- connection.getSomething() otherValue <- connection.getAnotherSomething(value) } yield otherValue result match { case Success(value) => … case NotFound => … case NotAuthorized => … }  Returns Try[T]  Type of value explicitly says that the client should deal with exceptions  The code is clean as concise  Exceptions is not an only case for Try-Failure monad. The monad called “Error” in generic case, example is coming
  • 25. Asynchronously blowing up mind  Writing async code is another level of complexity  In pure C# 2 (I suppose Java too) async code often ended up with spaghetti-like code  We are going to live in a non-blocking world
  • 26. Bright future  A Future is an object holding a value which may become available at some point.  Resolves in two possible ways  When a Future is completed with a value, we say that the future was successfully completed with that value.  When there has been an error, we say that the future completed with failure What is the difference with Error monad? Async! So someone will care about async!
  • 27. The magic of Future price: Future[Money] = nasdaq.getSharePrice(“AAPL”) Is value there? – Don’t know Could we do something with it? – Why not? price.map(p => costOfOurStock(p)) //returns Future price.flatMap( p => nasdaq.bid(“AAPL”, p-0.01, 10)) //Future on Future
  • 28. Future  Will not go deep into Promises-Futures  Future is a good example, where flatMap shines  flatMap abstracts everything from the developer except the operations on values  Concentration on happy path at the most extent
  • 29. Random distribution monad A value inside a monad is some random value of type T distributed according to some law A good an uncommon example of monad application trait Distribution[T] { def sample(): T def flatMap[TOut](f: T => Distribution[TOut]): Distribution[TOut] def map[TOut](f: T => TOut): Distribution[TOut] } Each time sample is called new random value is generated Source: https://github.com/mikegirkin/randommonad
  • 30. Implementation trait Distribution[T] { self => def sample(): T def flatMap[TOut](f: T => Distribution[TOut]): Distribution[TOut] = { new Distribution[TOut] { override def sample = f(self.sample()).sample() } } def map[TOut](f: T => TOut): Distribution[TOut] = { new Distribution[TOut] { override def sample = f(self.sample()) } } }
  • 31. A first real implementation A uniform distribution of discrete random values from the given alphabet def uniform[T](values: Array[T]): Distribution[T] = new Distribution[T] { override def sample: T = { val index = rnd.nextInt(values.size) values(index) } }
  • 32. Extracting distribution Results in sequence of (value, probability) def histo: Seq[(T, Double)] = { val n = 1000000 val map = scala.collection.mutable.Map[T, Double]() for(i <- 1 to n) { val s = sample() if(map.isDefinedAt(s)) map(s) = map(s) + 1.0/n else map(s) = 1.0/n } map.toSeq }
  • 33. What could we do? Ever played D&D game? def dice(sides: Int) = Distribution.uniform(Range(1, sides+1, 1)) val d6 = dice(6) val d20 = dice(20) val d3d6 = for { x <- d6 y <- d6 z <- d6 } yield x+y+z 18: 0.0046 17: 0.0139 16: 0.0278 15: 0.0464 14: 0.0692 13: 0.0972 12: 0.1156 11: 0.1251 10: 0.1255 9: 0.1161 8: 0.0970 7: 0.0694 6: 0.0463 5: 0.0274 4: 0.0140 3: 0.0047
  • 34. Drivers and accidents Say we have a crossroads with the yellow traffic lights at the moment, and to drivers approaching from the orthogonal directions. Drivers: 0.2 – aggressive, will accelerate with probability 0.9 0.6 – normal, will accelerate with probability 0.2 0.2 – cautious, will accelerate with probability 0.1 Let’s use the random monad
  • 35. Given distribution def given[T](probs: Seq[(Double, T)]): Distribution[T] = new Distribution[T] { //result in i.e. ((0.2 -> cautious), (0.8 -> normal), (1.0 -> aggressive)) val aggrProbs = probs .scanLeft(0.0)((p, x) => p + x._1) .drop(1) .zip(probs.map(_._2)) override def sample: T = { val r = rnd.nextDouble() aggrProbs.find(x => x._1 >= r).get._2 } }
  • 36. Keep code simple def aggressive = Distribution.given(Seq((0.9 -> true), (0.1 -> false))) def normal = Distribution.given(Seq((0.2 -> true), (0.8 -> false))) def cautious = Distribution.given(Seq((0.1 -> true), (0.9 -> false))) def driver = Distribution.given(Seq( (0.2 -> cautious), (0.6 -> normal), (0.2 -> aggressive) )) val collision = for { d1 <- driver d2 <- driver act1 <- d1 act2 <- d2 } yield act1 && act2 Results in: false: 0.8976 true: 0.1024
  • 37. A real code (still simplified) example Let’s say we want to implement user updating the ticket in the ticket-tracking system A usecase (happy path): user fills the form with the updated values, and presses “Update”. The system updates the ticket in the storage, and redirects to the ticket information page, and then sends the email notification. What can go wrong?  Invalid values submitted  There is no ticket to update  The user is not allowed update that ticket  The db could fail to perform the update
  • 38. Monad! Error monad is what we want! trait MyAppResult[T] case class MyAppSuccess[T](result: T) extends MyAppResult[T] trait MyAppFailure extends MyAppResult[Nothing] case class InvalidInput( errors: Seq[InputError]) extends MyAppFailure case object TicketNotFound extends MyAppFailure case object NoPermission extends MyAppFailure case object DbFailure extends MyAppFailure
  • 39. The code sketch val form = getUserInput() for { validatedInput <- validateForm(form) ticket <- retreiveTicket(validatedInput.ticketId) _ <- check(currentUser.canEditTicket(ticket)) updatedTicket <- updateTicket(ticket, validatedInput) _ <- saveTicket(updatedTicket) } yield updatedTicket updatedTicket match { case MyAppSuccess(ticket) => ... case InvalidInput(errors) => ... case TicketNotFound => ... ... }
  • 40. Recap: Monadic pattern 1. Get initial value enclosed in monad 2. Do something with the value enclosed, get monad 3. Do something with the value enclosed, get monad 4. … 5. PROFIT!!! Result resolution
  • 41. Recap  Monads is the way to execute some computation following the common rules  Monads is all about flatMap, nothing more  Monads is the way to abstract common rules and reuse them  It is not a rocket science, and you’ve already used them  Monads for everyday use:  Seq  Option  Try/Error  Future
  • 42. Some links  Erik Meijer - Contravariance is the Dual of Covariance (http://www.infoq.com/interviews/meijer-monads)  Principles of reactive programming (https://www.coursera.org/course/reactive)  Robert Martin - Monads within Clojure (https://www.youtube.com/watch?v=Usxf3aLimtU)  Dick Wall - What Have The Monads Ever Done For Us (https://www.youtube.com/watch?v=2IYNPUp751g)