SlideShare a Scribd company logo
1 of 54
Download to read offline
Playing with the State Monad
David Galichet	

Freelance Developer

Twitter : @dgalichet
Wait ! what’s a Monad ?
•

Functor

•

Monad

•

For comprehensions
Wait ! what’s a Monad ?
y !
r e
o d
g i
te s
a in
c
o ry
N o
e
th

•

Functor

•

Monad

•

For comprehensions
Functor
F is a Functor if there is a function :
map(fa: F[A])(f: A => B): F[B]!
that implements the following laws :
1. Identity : map(fa)(Id) == fa!
2. Composition : map(fa)( f ○ g ) ==
map(map(fa)(f))(g)
Functor
F can be seen as a context where a value A rely

F is a Functor if there is a function :
map(fa: F[A])(f: A => B): F[B]!
that implements the following laws :
1. Identity : map(fa)(Id) == fa!
2. Composition : map(fa)( f ○ g ) ==
map(map(fa)(f))(g)
Functor
F is a Functor if there are the following functions :
pure[A](a: A): F[A]!
map(fa: F[A])(f: A => B): F[B]!
Id is the Identity function

that implements the following laws
1. Identity : map(Id) == Id!

2. Composition : map( f ○ g ) == fmap(f) ○
fmap(g)
Functor
trait
def
def
def
}

Functor[F[+_]] {!
pure[A](a: A): F[A]!
map[A,B](fa: F[A])(f: A => B): F[B]!
lift[A,B](f: A => B): F[A] => F[B] = ???!
Functor
trait
def
!
def
!
def
}

Functor[F[+_]] {!
pure[A](a: A): F[A]!

Functor and Monads are also
known as typeclasses

map[A,B](fa: F[A])(f: A => B): F[B]!
lift[A,B](f: A => B): F[A] => F[B] = ???!
Functor
trait
def
!
def
!
def
{ fa:
!

}

Functor[F[_]] {!
pure[A](a: A): F[A]!
map[A,B](fa: F[A])(f: A => B): F[B]!
lift[A,B](f: A => B): F[A] => F[B] = !
F[A] => map(fa)(f) }!
Ex: Maybe is a Functor
sealed trait Maybe[+A]!
case class Value[+A](a: A) extends Maybe[A]!
case object Empty extends Maybe[Nothing]!
!

object Maybe {!
implicit val maybeIsAFunctor = new Functor[Maybe] {!
def pure[A](a: A): Maybe[A] = Value(a)!
def map[A, B](fa: Maybe[A])(f: A => B) = fa match {!
case Empty => Empty!
case Value(a) => Value(f(a))!
}!
}!
}
Ex: Maybe is a Functor
We define a generic function that double the content of a
Functor :
import monads.MaybeIsAFunctor!
def twice[F[+_]](fa: F[Int])(implicit FA: Functor[F]):
F[Int] = FA.map(fa){ x => x*2 }!
!

scala> twice(Value(4): Maybe[Int])!
res1: Value(8)
Monad
M is a Monad if M is an (Applicative) Functor and
there exists the following functions :
unit[A](a: A): M[A]!
bind[A,B](ma: M[A])(f: A => M[B]): M[B]!
Monad
and methods unit and bind implement the following
laws :
1. Left Identity : bind(unit(x))(f) == f(x) !
2. Right Identity : bind(ma)(unit) == ma!
3. Associativity :
bind(bind(ma)(f))(g) == bind(ma){ a =>
bind(f(a))(g) }
Monad
trait Monad[M[+_]] extends Functor[M] {!
def unit[A](a: A): M[A] = pure(a)!
!

def bind[A, B](ma: M[A])(f: A => M[B]): M[B]!
!

def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B] =
bind(ma)(f)!
}!
Ex : Maybe is a Monad
implicit val maybeIsAMonad = new Monad[Maybe] {!
def pure[A](a: A) = Value(a)!
!

def map[A, B](fa: Maybe[A])(f: (A) => B): M[B] = ???!
!

def bind[A, B](ma: Maybe[A])(f: A => Maybe[B]): M[B] =
ma match {!
case Empty => Empty!
case Value(a) => f(a)!
}!
}
Ex : Maybe is a Monad
implicit val maybeIsAMonad = new Monad[Maybe] {!
def pure[A](a: A) = Value(a)!
!

def map[A, B](fa: Maybe[A])(f: (A) => B) = bind(fa)
{ a => unit(f(a)) }!
!

def bind[A, B](ma: Maybe[A])(f: A => Maybe[B]): M[B] =
ma match {!
case Empty => Empty!
case Value(a) => f(a)!
}!
}
Ex : Maybe is a Monad
We define a generic function that add the content of two
Monads :
def add[M[+_]](ma: M[Int], mb: M[Int])(implicit MA:
Monad[M]): M[Int] = !
MA.bind(ma) { x => MA.map(mb) { y => x + y} }!
!

scala> import monads.maybeIsAMonad!
scala> add(Value(4): Maybe[Int], Value(2): Maybe[Int])!
res1: monads.Maybe[Int] = Value(6)
For comprehension
•

Scala provides For Comprehension to simplify
chaining of map and flatMap (equivalent to do
notation in Haskell)

•

At compilation, For Comprehension will be
transformed to a serie of flatMap and map
For comprehension
Scala For Comprehension needs that map and
flatMap to be defined on object directly (not using
typeclass). Here we define a MonadWrapper :
implicit class MonadWrapper[A, M[+_]](ma: M[A])(implicit
MA: Monad[M]) {!
def map[B](f: A => B): M[B] = MA.map(ma)(f)!
!

def flatMap[B](f: A => M[B]): M[B] = MA.flatMap(ma)(f)!
}
For comprehension
import monads.maybeIsAMonad!
!

def add2[M[+_]](ma: M[Int], mb: M[Int])(implicit MA:
Monad[M]): M[Int] = {!
import Monad.MonadWrapper!
for {!
a <- ma!
b <- mb!
} yield a + b!
}!
!

scala> import monads.maybeIsAMonad!
scala> add2(Value(4): Maybe[Int], Value(2): Maybe[Int])!
res2: monads.Maybe[Int] = Value(6)
Generic programming
def sequence[A, M[+_]](ms: List[M[A]])(implicit MA:
Monad[M]): M[List[A]] = ms match {!
case Nil => MA.unit(List.empty[A])!
case head::tail => for {!
x <- head!
xs <- sequence(tail)!
} yield x::xs!
}!
!

import monads.maybeIsAMonad!
!

scala> Monad.sequence(List(Value(1): Maybe[Int],
Value(2): Maybe[Int]))!
res3: monads.Maybe[List[Int]] = Value(List(1, 2))
Let’s continue our journey
with a simple problem
3
2
1
0
0

1

2

3
Rules of the game
•

We want to simulate two robots moving through a
nxm playground

•

Each robot can either turn on a direction (North,
South, East, West) or move one step forward

•

Robots move or turn according to instructions
Rules of the game
•

A robot can’t go out of the playground

•

A robot will be blocked if another robot is on the
place

•

Some coins are spread on the playground

•

Robots gather coins when they move over it
Think about this game
•

It appears that we will deal with many states :
•

Playground with its coins

•

Robots with their positions and gathered coins
We want functional purity
•

Functional Purity has many advantages like
composability, idempotence, maintainability and
thread safety

•

We need to find a way to deal with states and
remain pure
Dealing with states
S => (S, A)
•

S is the type of a state and A the type of a
computation

•

The outcome of this function is a new state and a
result
Chaining states
computations
def chainStOps(!
c1: S => (S, A), !
c2: S => (S, A)!
): S => (S, A) = { s =>!
val (s1, _) = c1(s)!
c2(s1)!
}

Repeated many times, this can be error prone !
Introducing State Monad

The aim of the state monad is to abstract over state
manipulations
Introducing State Monad
trait State[S, +A] {!
def run(initial: S): (S, A)!
def map[B](f: A => B): State[S, B] = ???!
def flatMap[B](f: A => State[S, B]): State[S, B] = ???!
}!
!

object State {!
def apply[S, A](f: S => (S, A)): State[S, A] = ???!
}
Introducing State Monad
trait State[S, +A] {!
def run(initial: S): (S, A)!
def map[B](f: A => B): State[S, B] = ???!
def flatMap[B](f: A => State[S, B]): State[S, B] = ???!
}!
!

object State {!
def apply[S, A](f: S => (S, A)): State[S, A] = !
new State[S, A] {!
def run(initial: S): (S, A) = f(initial)!
}!
State Monad embed computation !
}
Introducing State Monad
trait State[S, +A] {!
def run(initial: S): (S, A)!
!

def map[B](f: A => B): State[S, B] = State { s =>!
val (s1, a) = run(s)!
(s1, f(a))!
Don’t forget the definition:
}!
State.apply(S => (S, A)): State[S,A]
!
!
!

def flatMap[B](f: A => State[S, B]): State[S, B] = ???!
}
Introducing State Monad

trait State[S, +A] {!
def run(initial: S): (S, A)!
!

def map[B](f: A => B): State[S, B] = State { s =>!
val (s1, a) = run(s)!
(s1, f(a))!
}!
Don’t forget the definition:
!
State.apply(S => (S, A)): State[S,A]
!
!

def flatMap[B](f: A => State[S, B]): State[S, B] = !
State { s =>!
val (s1, a) = run(s)!
f(a).run(s1)!
}!
}
Coming back to our game !
•

We drive robots using a list of instructions

sealed trait Instruction!
case object L extends Instruction // turn Left!
case object R extends Instruction // turn Right!
case object A extends Instruction // Go on
Coming back to our game !
•

Each robot has a direction

sealed trait Direction {!
def turn(i: Instruction): Direction!
}!
case object North extends Direction {!
def turn(i: Instruction) = i match {!
case L => West!
case R => East!
case _ => this!
}!
}!
case object South extends Direction { ... }!
case object East extends Direction { ... }!
case object West extends Direction { ... }
Coming back to our game !
•

A direction and a location define a position

case class Point(x: Int, y: Int)!
!

case class Position(point: Point, dir: Direction) {!
def move(s: Playground): Position = {!
val p1 = dir match {!
case North => copy(point = point.copy(y = point.y + 1))!
case South => ...!
}!
if (s.isPossiblePosition(p1)) p1 else this!
}!
def turn(instruction: Instruction): Position =
!
copy(direction = direction.turn(instruction))!
}
Coming back to our game !
•

And each Robot is a player with a Score

sealed trait Player!
case object R1 extends Player!
case object R2 extends Player!
!

case class Score(player: Player, score: Int)
Coming back to our game !
•

The state of each Robot is defined as :

case class Robot(!
player: Player, !
positions: List[Position], !
coins: List[Point] = Nil) {!
lazy val currentPosition = positions.head!
!

lazy val score = Score(player, coins.size)!
!

def addPosition(next: Position) = copy(positions =
next::positions)!
!

def addCoin(coin: Point) = copy(coins = coin::coins)!
}
Coming back to our game !
•

Robots evolve in a playground :

case class Playground(!
bottomLeft: Point, topRight: Point, !
coins: Set[Point],!
r1: Robot, r2: Robot) {!
!

def isInPlayground(point: Point): Boolean =!
bottomLeft.x <= point.x && ...!
!

def isPossiblePosition(pos: Position): Boolean = ...!
!

lazy val scores = (r1.score, r2.score)!
!

def swapRobots(): Playground = copy(r1 = r2, r2 = r1)!
}
Look what we did
•

a set of Instructions,

•

a Position composed with Points and Direction,

•

a definition for Players and Score,

•

a way to define Robot state

•

and a way to define Playground state
Let put these all together !
•

Now, we need a method to process a single
instruction

•

And a method to process all instructions

•

The expected result is a State Monad that will be
run with the initial state of the playground
Processing a single
instruction
def processInstruction(i: Instruction)(s: Playground):
Playground = {!
val next = i match {!
case A => s.r1.currentPosition.move(s)!
case i => s.r1.currentPosition.turn(i)!
}!
!

if (s.coins.contains(next.point)) {!
s.copy(!
coins = s.coins - next.point, !
r1 = s.r1.addCoin(next.point).addPosition(next)!
)!
} else {!
s.copy(r1 = s.r1.addPosition(next))!
}!
}
Processing a single
instruction
def processInstruction(i: Instruction)(s: Playground):
Playground = {!
val next = i match {!
case A => s.r1.currentPosition.move(s)!
case i => s.r1.currentPosition.turn(i)!
}!
We always process the robot on first position !
!
Robots will be swapped alternatively.
if (s.coins.contains(next.point)) {!
s.copy(!
coins = s.coins - next.point, !
r1 = s.r1.addCoin(next.point).addPosition(next)!
)!
} else {!
s.copy(r1 = s.r1.addPosition(next))!
}!
}
Quick reminder
trait State[S, +A] {!
def run(initial: S): (S, A)!
def map[B](f: A => B): State[S, B] = State { s =>!
val (s1, a) = run(s)!
(s1, f(a))!
}!
def flatMap[B](f: A => State[S, B]): State[S, B] = !
State { s =>!
val (s1, a) = run(s)!
f(a).run(s1)!
}!
}!
object State {!
def apply[S, A](f: S => (S, A)): State[S, A] =!
new State[S, A] {!
def run(initial: S): (S, A) = f(initial)!
}!
Introducing new
combinators
trait State[S, +A] {!
...!
}!
object State {!
def apply[S, A](f: S => (S, A)): State[S, A] =!
new State[S, A] {!
def run(initial: S): (S, A) = f(initial)!
}!
!

def get[S]: State[S, S] = State { s => (s, s) }!
!

def gets[S, A](f: S => A): State[S, A] = !
State { s => (s, f(s)) }!
}
Here comes the magic !
def compileInstructions(!
i1: List[Instruction], !
i2: List[Instruction]!
): State[Playground, (Score, Score)] = i1 match {!
case Nil if i2 == Nil => State.gets(_.scores)!
case Nil => State[Playground, (Score, Score)] { s =>
(s.swapRobots(), s.scores) !
}.flatMap { _ => compileInstructions(i2, i1) }!
case head::tail => State[Playground, (Score, Score)] !
{ s =>!
val s1 = processInstruction(head)(s)!
(s1.swapRobots(), s1.scores)!
}.flatMap { _ => compileInstructions(i2, tail) }!
}

!
Here comes the magic !
def compileInstructions(!
i1: List[Instruction], !
i2: List[Instruction]!
): State[Playground, (Score, Score)] = i1 match {!
case Nil if i2 == Nil => State.gets(_.scores)!
case Nil => State[Playground, (Score, Score)] { s =>
(s.swapRobots(), i1 and i2 are!
s.scores) empty, we return a State
If both
}.flatMap { _ => compileInstructions(i2, i1) }!
Monad with the run method implementation :
case head::tail => State[Playground, (Score, Score)] !
s => (s, s.scores)!
{ s =>!
This will return the Playground passed in argument
val s1 = processInstruction(head)(s)!
and the score as result.
(s1.swapRobots(), s1.scores)!
}.flatMap { _ => compileInstructions(i2, tail) }!
}

!
Here comes the magic !
def compileInstructions(!
i1: List[Instruction], !
i2: List[Instruction]!
): State[Playground, (Score, Score)] = i1 match {!
case Nil if i2 == Nil => State.gets(_.scores)!
case Nil => State[Playground, (Score, Score)] { s =>
(s.swapRobots(), s.scores) !
}.flatMap { _ => compileInstructions(i2, Nil) }!
case head::tail => State[Playground, (Score, Score)] !
{ s =>! If i1 is empty, we return a State Monad with a run
val s1 method that swap robots in Playground and returns
= processInstruction(head)(s)!
(s1.swapRobots(), s1.scores)!
scores.
}.flatMap { _we chain it with the processing of instructions for
Then => compileInstructions(i2, tail) }!
}
the second list.

!
Here comes the magic !
def compileInstructions(!
i1: List[Instruction], i1 and return a new Playground where
We process !
i2: List[Instruction]!
robots are swapped.
): State[Playground, (Score, Score)] = i1 matchinstructions
Then we chain it with the processing of the {!
case Nil if i2 == Nil of i1.
i2 and tail => State.gets(_.scores)!
case Nil => State[Playground, (Score, Score)] { !s =>
Lists of instructions are processed alternatively
(s.swapRobots(), s.scores) !
}.flatMap { _ => compileInstructions(i2, i1) }!
case head::tail => State[Playground, (Score, Score)] !
{ s =>!
val s1 = processInstruction(head)(s)!
(s1.swapRobots(), s1.scores)!
}.flatMap { _ => compileInstructions(i2, tail) }!
}

!
Here comes the magic !
def compileInstructions(!
i1: List[Instruction], !
i2: List[Instruction]!
): State[Playground, (Score, Score)] = i1 match {!
case Nil if i2 == Nil => State.gets(_.scores)!
case Nil => State[Playground, (Score, Score)] { s =>
(s.swapRobots(), s.scores) !
}.flatMap { _ => compileInstructions(i2, i1) }!
case head::tail => State[Playground, (Score, Score)] !
{ s =>!
val s1 = processInstruction(head)(s)!
(s1.swapRobots(), s1.scores)!
}.flatMap { _ => compileInstructions(i2, tail) }!
}

!
Using for comprehensions
def getPositions(p: Playground): (Position, Position) =
(p.r1.currentPosition, p.r2.currentPosition)!
!

def enhanceResult(!
i1: List[Instruction], !
i2: List[Instruction]): State[Playground, (String,
(Position, Position))] = {!
for {!
scores <- compileInstructions(i1, i2)!
positions <- State.gets(getPositions)!
} yield (declareWinners(scores), positions)!
}
Conclusion

•

State Monad simplify computations on states

•

Use it whenever you want to manipulate states in a
purely functional (parsing, caching, validation ...)
To learn more about State
Monad
•

Functional programming in Scala by Paul Chiusano
and Rúnar Bjarnason - This book is awesome !

•

State Monad keynote by Michael Pilquist - https://
speakerdeck.com/mpilquist/scalaz-state-monad

•

Learning scalaz by Eugene Yokota - http://
eed3si9n.com/learning-scalaz/State.html
Questions ?

More Related Content

What's hot

Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverseLuka Jacobowitz
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type ClassesJohn De Goes
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FPLuka Jacobowitz
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaJorge Vásquez
 
λ | Lenses
λ | Lensesλ | Lenses
λ | LensesOpen-IT
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The WildStackMob Inc
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class PatternsJohn De Goes
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them AllJohn De Goes
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't FreeKelley Robinson
 
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
 
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...Philip Schwarz
 
Scala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereldScala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereldWerner Hofstra
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceAlexey Raga
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsJohn De Goes
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free MonadsJohn De Goes
 
Optics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the wholeOptics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the wholeIlan Godik
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoidsLuka Jacobowitz
 
OSCON Presentation: Developing High Performance Websites and Modern Apps with...
OSCON Presentation: Developing High Performance Websites and Modern Apps with...OSCON Presentation: Developing High Performance Websites and Modern Apps with...
OSCON Presentation: Developing High Performance Websites and Modern Apps with...Doris Chen
 
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }Atomically { Delete Your Actors }
Atomically { Delete Your Actors }John De Goes
 

What's hot (20)

Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverse
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in Scala
 
λ | Lenses
λ | Lensesλ | Lenses
λ | Lenses
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class Patterns
 
Beyond Scala Lens
Beyond Scala LensBeyond Scala Lens
Beyond Scala Lens
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't Free
 
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
 
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
 
Scala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereldScala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereld
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritance
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
 
Optics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the wholeOptics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the whole
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoids
 
OSCON Presentation: Developing High Performance Websites and Modern Apps with...
OSCON Presentation: Developing High Performance Websites and Modern Apps with...OSCON Presentation: Developing High Performance Websites and Modern Apps with...
OSCON Presentation: Developing High Performance Websites and Modern Apps with...
 
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
 

Viewers also liked

하스켈 프로그래밍 입문 3
하스켈 프로그래밍 입문 3하스켈 프로그래밍 입문 3
하스켈 프로그래밍 입문 3Kwang Yul Seo
 
(2015 06-16) Three Approaches to Monads
(2015 06-16) Three Approaches to Monads(2015 06-16) Three Approaches to Monads
(2015 06-16) Three Approaches to MonadsLawrence Evans
 
Functional Programming by Examples using Haskell
Functional Programming by Examples using HaskellFunctional Programming by Examples using Haskell
Functional Programming by Examples using Haskellgoncharenko
 
전자책산업동향과 서비스 모델 (Slide Share)
전자책산업동향과 서비스 모델 (Slide Share)전자책산업동향과 서비스 모델 (Slide Share)
전자책산업동향과 서비스 모델 (Slide Share)Joong Ho Lee
 
Real-World Functional Programming @ Incubaid
Real-World Functional Programming @ IncubaidReal-World Functional Programming @ Incubaid
Real-World Functional Programming @ IncubaidNicolas Trangez
 
Haskell study 15
Haskell study 15Haskell study 15
Haskell study 15Nam Hyeonuk
 
Sponsorship Opportunities | Customer Experience Conference
Sponsorship Opportunities | Customer Experience ConferenceSponsorship Opportunities | Customer Experience Conference
Sponsorship Opportunities | Customer Experience ConferenceThedijuliusgroup
 
Proposal presentation
Proposal presentationProposal presentation
Proposal presentationHarry Barnes
 
Perl 5.16 new features
Perl 5.16 new featuresPerl 5.16 new features
Perl 5.16 new featuresPavel Vlasov
 
Graficas en matlab(1er grupo tele)
Graficas en matlab(1er grupo tele)Graficas en matlab(1er grupo tele)
Graficas en matlab(1er grupo tele)Jose Isaias
 
Planning for draft 5
Planning for draft 5Planning for draft 5
Planning for draft 5debbie14
 
Primero egf presentation print
Primero egf presentation printPrimero egf presentation print
Primero egf presentation printprimero_mining
 
Dps stages of development
Dps  stages of developmentDps  stages of development
Dps stages of developmentchaggarg1
 
Sprawl Products Top to MMA Gear
Sprawl Products Top to MMA GearSprawl Products Top to MMA Gear
Sprawl Products Top to MMA Gearhbwmike
 
Young people project ppt
Young people project pptYoung people project ppt
Young people project pptsvhughes1028
 

Viewers also liked (20)

하스켈 프로그래밍 입문 3
하스켈 프로그래밍 입문 3하스켈 프로그래밍 입문 3
하스켈 프로그래밍 입문 3
 
(2015 06-16) Three Approaches to Monads
(2015 06-16) Three Approaches to Monads(2015 06-16) Three Approaches to Monads
(2015 06-16) Three Approaches to Monads
 
Functional Programming by Examples using Haskell
Functional Programming by Examples using HaskellFunctional Programming by Examples using Haskell
Functional Programming by Examples using Haskell
 
전자책산업동향과 서비스 모델 (Slide Share)
전자책산업동향과 서비스 모델 (Slide Share)전자책산업동향과 서비스 모델 (Slide Share)
전자책산업동향과 서비스 모델 (Slide Share)
 
Real-World Functional Programming @ Incubaid
Real-World Functional Programming @ IncubaidReal-World Functional Programming @ Incubaid
Real-World Functional Programming @ Incubaid
 
Haskell study 15
Haskell study 15Haskell study 15
Haskell study 15
 
The monad fear
The monad fearThe monad fear
The monad fear
 
Primero ar-2011 final
Primero ar-2011 finalPrimero ar-2011 final
Primero ar-2011 final
 
Sponsorship Opportunities | Customer Experience Conference
Sponsorship Opportunities | Customer Experience ConferenceSponsorship Opportunities | Customer Experience Conference
Sponsorship Opportunities | Customer Experience Conference
 
Proposal presentation
Proposal presentationProposal presentation
Proposal presentation
 
Perl 5.16 new features
Perl 5.16 new featuresPerl 5.16 new features
Perl 5.16 new features
 
Graficas en matlab(1er grupo tele)
Graficas en matlab(1er grupo tele)Graficas en matlab(1er grupo tele)
Graficas en matlab(1er grupo tele)
 
Planning for draft 5
Planning for draft 5Planning for draft 5
Planning for draft 5
 
Primero egf presentation print
Primero egf presentation printPrimero egf presentation print
Primero egf presentation print
 
Wahyu widya
Wahyu widyaWahyu widya
Wahyu widya
 
Dps stages of development
Dps  stages of developmentDps  stages of development
Dps stages of development
 
Sprawl Products Top to MMA Gear
Sprawl Products Top to MMA GearSprawl Products Top to MMA Gear
Sprawl Products Top to MMA Gear
 
Motivational
MotivationalMotivational
Motivational
 
Young people project ppt
Young people project pptYoung people project ppt
Young people project ppt
 
Kitchen Cupboards
Kitchen CupboardsKitchen Cupboards
Kitchen Cupboards
 

Similar to Playing with the State Monad and Functional Programming

The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator PatternEric Torreborre
 
Functional IO and Effects
Functional IO and EffectsFunctional IO and Effects
Functional IO and EffectsDylan Forciea
 
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
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patternsleague
 
Drinking the free kool-aid
Drinking the free kool-aidDrinking the free kool-aid
Drinking the free kool-aidDavid Hoyt
 
Go Containers
Go ContainersGo Containers
Go Containersjgrahamc
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adtsHang Zhao
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For GoogleEleanor McHugh
 
Monadologie
MonadologieMonadologie
Monadologieleague
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
Scalaエンジニアのためのモナド入門
Scalaエンジニアのためのモナド入門Scalaエンジニアのためのモナド入門
Scalaエンジニアのためのモナド入門Takashi Imahiro
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2Hang Zhao
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Philip Schwarz
 
Grokking Monads in Scala
Grokking Monads in ScalaGrokking Monads in Scala
Grokking Monads in ScalaTim Dalton
 
Five Languages in a Moment
Five Languages in a MomentFive Languages in a Moment
Five Languages in a MomentSergio Gil
 
Scaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazScaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazHeiko Seeberger
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxEleanor McHugh
 
Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Send + More = Money – Let’s mash 2 monads to solve a simple CSPSend + More = Money – Let’s mash 2 monads to solve a simple CSP
Send + More = Money – Let’s mash 2 monads to solve a simple CSPFilippo Vitale
 

Similar to Playing with the State Monad and Functional Programming (20)

The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
 
Functional IO and Effects
Functional IO and EffectsFunctional IO and Effects
Functional IO and Effects
 
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)
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
Drinking the free kool-aid
Drinking the free kool-aidDrinking the free kool-aid
Drinking the free kool-aid
 
Go Containers
Go ContainersGo Containers
Go Containers
 
Go Containers
Go ContainersGo Containers
Go Containers
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adts
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
 
Monadologie
MonadologieMonadologie
Monadologie
 
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
 
Scalaエンジニアのためのモナド入門
Scalaエンジニアのためのモナド入門Scalaエンジニアのためのモナド入門
Scalaエンジニアのためのモナド入門
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'
 
Grokking Monads in Scala
Grokking Monads in ScalaGrokking Monads in Scala
Grokking Monads in Scala
 
Five Languages in a Moment
Five Languages in a MomentFive Languages in a Moment
Five Languages in a Moment
 
Scaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazScaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of Scalaz
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
 
Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Send + More = Money – Let’s mash 2 monads to solve a simple CSPSend + More = Money – Let’s mash 2 monads to solve a simple CSP
Send + More = Money – Let’s mash 2 monads to solve a simple CSP
 
Functor Composition
Functor CompositionFunctor Composition
Functor Composition
 

Recently uploaded

"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 

Recently uploaded (20)

"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 

Playing with the State Monad and Functional Programming

  • 1. Playing with the State Monad David Galichet Freelance Developer Twitter : @dgalichet
  • 2. Wait ! what’s a Monad ? • Functor • Monad • For comprehensions
  • 3. Wait ! what’s a Monad ? y ! r e o d g i te s a in c o ry N o e th • Functor • Monad • For comprehensions
  • 4. Functor F is a Functor if there is a function : map(fa: F[A])(f: A => B): F[B]! that implements the following laws : 1. Identity : map(fa)(Id) == fa! 2. Composition : map(fa)( f ○ g ) == map(map(fa)(f))(g)
  • 5. Functor F can be seen as a context where a value A rely F is a Functor if there is a function : map(fa: F[A])(f: A => B): F[B]! that implements the following laws : 1. Identity : map(fa)(Id) == fa! 2. Composition : map(fa)( f ○ g ) == map(map(fa)(f))(g)
  • 6. Functor F is a Functor if there are the following functions : pure[A](a: A): F[A]! map(fa: F[A])(f: A => B): F[B]! Id is the Identity function that implements the following laws 1. Identity : map(Id) == Id! 2. Composition : map( f ○ g ) == fmap(f) ○ fmap(g)
  • 7. Functor trait def def def } Functor[F[+_]] {! pure[A](a: A): F[A]! map[A,B](fa: F[A])(f: A => B): F[B]! lift[A,B](f: A => B): F[A] => F[B] = ???!
  • 8. Functor trait def ! def ! def } Functor[F[+_]] {! pure[A](a: A): F[A]! Functor and Monads are also known as typeclasses map[A,B](fa: F[A])(f: A => B): F[B]! lift[A,B](f: A => B): F[A] => F[B] = ???!
  • 9. Functor trait def ! def ! def { fa: ! } Functor[F[_]] {! pure[A](a: A): F[A]! map[A,B](fa: F[A])(f: A => B): F[B]! lift[A,B](f: A => B): F[A] => F[B] = ! F[A] => map(fa)(f) }!
  • 10. Ex: Maybe is a Functor sealed trait Maybe[+A]! case class Value[+A](a: A) extends Maybe[A]! case object Empty extends Maybe[Nothing]! ! object Maybe {! implicit val maybeIsAFunctor = new Functor[Maybe] {! def pure[A](a: A): Maybe[A] = Value(a)! def map[A, B](fa: Maybe[A])(f: A => B) = fa match {! case Empty => Empty! case Value(a) => Value(f(a))! }! }! }
  • 11. Ex: Maybe is a Functor We define a generic function that double the content of a Functor : import monads.MaybeIsAFunctor! def twice[F[+_]](fa: F[Int])(implicit FA: Functor[F]): F[Int] = FA.map(fa){ x => x*2 }! ! scala> twice(Value(4): Maybe[Int])! res1: Value(8)
  • 12. Monad M is a Monad if M is an (Applicative) Functor and there exists the following functions : unit[A](a: A): M[A]! bind[A,B](ma: M[A])(f: A => M[B]): M[B]!
  • 13. Monad and methods unit and bind implement the following laws : 1. Left Identity : bind(unit(x))(f) == f(x) ! 2. Right Identity : bind(ma)(unit) == ma! 3. Associativity : bind(bind(ma)(f))(g) == bind(ma){ a => bind(f(a))(g) }
  • 14. Monad trait Monad[M[+_]] extends Functor[M] {! def unit[A](a: A): M[A] = pure(a)! ! def bind[A, B](ma: M[A])(f: A => M[B]): M[B]! ! def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B] = bind(ma)(f)! }!
  • 15. Ex : Maybe is a Monad implicit val maybeIsAMonad = new Monad[Maybe] {! def pure[A](a: A) = Value(a)! ! def map[A, B](fa: Maybe[A])(f: (A) => B): M[B] = ???! ! def bind[A, B](ma: Maybe[A])(f: A => Maybe[B]): M[B] = ma match {! case Empty => Empty! case Value(a) => f(a)! }! }
  • 16. Ex : Maybe is a Monad implicit val maybeIsAMonad = new Monad[Maybe] {! def pure[A](a: A) = Value(a)! ! def map[A, B](fa: Maybe[A])(f: (A) => B) = bind(fa) { a => unit(f(a)) }! ! def bind[A, B](ma: Maybe[A])(f: A => Maybe[B]): M[B] = ma match {! case Empty => Empty! case Value(a) => f(a)! }! }
  • 17. Ex : Maybe is a Monad We define a generic function that add the content of two Monads : def add[M[+_]](ma: M[Int], mb: M[Int])(implicit MA: Monad[M]): M[Int] = ! MA.bind(ma) { x => MA.map(mb) { y => x + y} }! ! scala> import monads.maybeIsAMonad! scala> add(Value(4): Maybe[Int], Value(2): Maybe[Int])! res1: monads.Maybe[Int] = Value(6)
  • 18. For comprehension • Scala provides For Comprehension to simplify chaining of map and flatMap (equivalent to do notation in Haskell) • At compilation, For Comprehension will be transformed to a serie of flatMap and map
  • 19. For comprehension Scala For Comprehension needs that map and flatMap to be defined on object directly (not using typeclass). Here we define a MonadWrapper : implicit class MonadWrapper[A, M[+_]](ma: M[A])(implicit MA: Monad[M]) {! def map[B](f: A => B): M[B] = MA.map(ma)(f)! ! def flatMap[B](f: A => M[B]): M[B] = MA.flatMap(ma)(f)! }
  • 20. For comprehension import monads.maybeIsAMonad! ! def add2[M[+_]](ma: M[Int], mb: M[Int])(implicit MA: Monad[M]): M[Int] = {! import Monad.MonadWrapper! for {! a <- ma! b <- mb! } yield a + b! }! ! scala> import monads.maybeIsAMonad! scala> add2(Value(4): Maybe[Int], Value(2): Maybe[Int])! res2: monads.Maybe[Int] = Value(6)
  • 21. Generic programming def sequence[A, M[+_]](ms: List[M[A]])(implicit MA: Monad[M]): M[List[A]] = ms match {! case Nil => MA.unit(List.empty[A])! case head::tail => for {! x <- head! xs <- sequence(tail)! } yield x::xs! }! ! import monads.maybeIsAMonad! ! scala> Monad.sequence(List(Value(1): Maybe[Int], Value(2): Maybe[Int]))! res3: monads.Maybe[List[Int]] = Value(List(1, 2))
  • 22. Let’s continue our journey with a simple problem 3 2 1 0 0 1 2 3
  • 23. Rules of the game • We want to simulate two robots moving through a nxm playground • Each robot can either turn on a direction (North, South, East, West) or move one step forward • Robots move or turn according to instructions
  • 24. Rules of the game • A robot can’t go out of the playground • A robot will be blocked if another robot is on the place • Some coins are spread on the playground • Robots gather coins when they move over it
  • 25. Think about this game • It appears that we will deal with many states : • Playground with its coins • Robots with their positions and gathered coins
  • 26. We want functional purity • Functional Purity has many advantages like composability, idempotence, maintainability and thread safety • We need to find a way to deal with states and remain pure
  • 27. Dealing with states S => (S, A) • S is the type of a state and A the type of a computation • The outcome of this function is a new state and a result
  • 28. Chaining states computations def chainStOps(! c1: S => (S, A), ! c2: S => (S, A)! ): S => (S, A) = { s =>! val (s1, _) = c1(s)! c2(s1)! } Repeated many times, this can be error prone !
  • 29. Introducing State Monad The aim of the state monad is to abstract over state manipulations
  • 30. Introducing State Monad trait State[S, +A] {! def run(initial: S): (S, A)! def map[B](f: A => B): State[S, B] = ???! def flatMap[B](f: A => State[S, B]): State[S, B] = ???! }! ! object State {! def apply[S, A](f: S => (S, A)): State[S, A] = ???! }
  • 31. Introducing State Monad trait State[S, +A] {! def run(initial: S): (S, A)! def map[B](f: A => B): State[S, B] = ???! def flatMap[B](f: A => State[S, B]): State[S, B] = ???! }! ! object State {! def apply[S, A](f: S => (S, A)): State[S, A] = ! new State[S, A] {! def run(initial: S): (S, A) = f(initial)! }! State Monad embed computation ! }
  • 32. Introducing State Monad trait State[S, +A] {! def run(initial: S): (S, A)! ! def map[B](f: A => B): State[S, B] = State { s =>! val (s1, a) = run(s)! (s1, f(a))! Don’t forget the definition: }! State.apply(S => (S, A)): State[S,A] ! ! ! def flatMap[B](f: A => State[S, B]): State[S, B] = ???! }
  • 33. Introducing State Monad trait State[S, +A] {! def run(initial: S): (S, A)! ! def map[B](f: A => B): State[S, B] = State { s =>! val (s1, a) = run(s)! (s1, f(a))! }! Don’t forget the definition: ! State.apply(S => (S, A)): State[S,A] ! ! def flatMap[B](f: A => State[S, B]): State[S, B] = ! State { s =>! val (s1, a) = run(s)! f(a).run(s1)! }! }
  • 34. Coming back to our game ! • We drive robots using a list of instructions sealed trait Instruction! case object L extends Instruction // turn Left! case object R extends Instruction // turn Right! case object A extends Instruction // Go on
  • 35. Coming back to our game ! • Each robot has a direction sealed trait Direction {! def turn(i: Instruction): Direction! }! case object North extends Direction {! def turn(i: Instruction) = i match {! case L => West! case R => East! case _ => this! }! }! case object South extends Direction { ... }! case object East extends Direction { ... }! case object West extends Direction { ... }
  • 36. Coming back to our game ! • A direction and a location define a position case class Point(x: Int, y: Int)! ! case class Position(point: Point, dir: Direction) {! def move(s: Playground): Position = {! val p1 = dir match {! case North => copy(point = point.copy(y = point.y + 1))! case South => ...! }! if (s.isPossiblePosition(p1)) p1 else this! }! def turn(instruction: Instruction): Position = ! copy(direction = direction.turn(instruction))! }
  • 37. Coming back to our game ! • And each Robot is a player with a Score sealed trait Player! case object R1 extends Player! case object R2 extends Player! ! case class Score(player: Player, score: Int)
  • 38. Coming back to our game ! • The state of each Robot is defined as : case class Robot(! player: Player, ! positions: List[Position], ! coins: List[Point] = Nil) {! lazy val currentPosition = positions.head! ! lazy val score = Score(player, coins.size)! ! def addPosition(next: Position) = copy(positions = next::positions)! ! def addCoin(coin: Point) = copy(coins = coin::coins)! }
  • 39. Coming back to our game ! • Robots evolve in a playground : case class Playground(! bottomLeft: Point, topRight: Point, ! coins: Set[Point],! r1: Robot, r2: Robot) {! ! def isInPlayground(point: Point): Boolean =! bottomLeft.x <= point.x && ...! ! def isPossiblePosition(pos: Position): Boolean = ...! ! lazy val scores = (r1.score, r2.score)! ! def swapRobots(): Playground = copy(r1 = r2, r2 = r1)! }
  • 40. Look what we did • a set of Instructions, • a Position composed with Points and Direction, • a definition for Players and Score, • a way to define Robot state • and a way to define Playground state
  • 41. Let put these all together ! • Now, we need a method to process a single instruction • And a method to process all instructions • The expected result is a State Monad that will be run with the initial state of the playground
  • 42. Processing a single instruction def processInstruction(i: Instruction)(s: Playground): Playground = {! val next = i match {! case A => s.r1.currentPosition.move(s)! case i => s.r1.currentPosition.turn(i)! }! ! if (s.coins.contains(next.point)) {! s.copy(! coins = s.coins - next.point, ! r1 = s.r1.addCoin(next.point).addPosition(next)! )! } else {! s.copy(r1 = s.r1.addPosition(next))! }! }
  • 43. Processing a single instruction def processInstruction(i: Instruction)(s: Playground): Playground = {! val next = i match {! case A => s.r1.currentPosition.move(s)! case i => s.r1.currentPosition.turn(i)! }! We always process the robot on first position ! ! Robots will be swapped alternatively. if (s.coins.contains(next.point)) {! s.copy(! coins = s.coins - next.point, ! r1 = s.r1.addCoin(next.point).addPosition(next)! )! } else {! s.copy(r1 = s.r1.addPosition(next))! }! }
  • 44. Quick reminder trait State[S, +A] {! def run(initial: S): (S, A)! def map[B](f: A => B): State[S, B] = State { s =>! val (s1, a) = run(s)! (s1, f(a))! }! def flatMap[B](f: A => State[S, B]): State[S, B] = ! State { s =>! val (s1, a) = run(s)! f(a).run(s1)! }! }! object State {! def apply[S, A](f: S => (S, A)): State[S, A] =! new State[S, A] {! def run(initial: S): (S, A) = f(initial)! }!
  • 45. Introducing new combinators trait State[S, +A] {! ...! }! object State {! def apply[S, A](f: S => (S, A)): State[S, A] =! new State[S, A] {! def run(initial: S): (S, A) = f(initial)! }! ! def get[S]: State[S, S] = State { s => (s, s) }! ! def gets[S, A](f: S => A): State[S, A] = ! State { s => (s, f(s)) }! }
  • 46. Here comes the magic ! def compileInstructions(! i1: List[Instruction], ! i2: List[Instruction]! ): State[Playground, (Score, Score)] = i1 match {! case Nil if i2 == Nil => State.gets(_.scores)! case Nil => State[Playground, (Score, Score)] { s => (s.swapRobots(), s.scores) ! }.flatMap { _ => compileInstructions(i2, i1) }! case head::tail => State[Playground, (Score, Score)] ! { s =>! val s1 = processInstruction(head)(s)! (s1.swapRobots(), s1.scores)! }.flatMap { _ => compileInstructions(i2, tail) }! } !
  • 47. Here comes the magic ! def compileInstructions(! i1: List[Instruction], ! i2: List[Instruction]! ): State[Playground, (Score, Score)] = i1 match {! case Nil if i2 == Nil => State.gets(_.scores)! case Nil => State[Playground, (Score, Score)] { s => (s.swapRobots(), i1 and i2 are! s.scores) empty, we return a State If both }.flatMap { _ => compileInstructions(i2, i1) }! Monad with the run method implementation : case head::tail => State[Playground, (Score, Score)] ! s => (s, s.scores)! { s =>! This will return the Playground passed in argument val s1 = processInstruction(head)(s)! and the score as result. (s1.swapRobots(), s1.scores)! }.flatMap { _ => compileInstructions(i2, tail) }! } !
  • 48. Here comes the magic ! def compileInstructions(! i1: List[Instruction], ! i2: List[Instruction]! ): State[Playground, (Score, Score)] = i1 match {! case Nil if i2 == Nil => State.gets(_.scores)! case Nil => State[Playground, (Score, Score)] { s => (s.swapRobots(), s.scores) ! }.flatMap { _ => compileInstructions(i2, Nil) }! case head::tail => State[Playground, (Score, Score)] ! { s =>! If i1 is empty, we return a State Monad with a run val s1 method that swap robots in Playground and returns = processInstruction(head)(s)! (s1.swapRobots(), s1.scores)! scores. }.flatMap { _we chain it with the processing of instructions for Then => compileInstructions(i2, tail) }! } the second list. !
  • 49. Here comes the magic ! def compileInstructions(! i1: List[Instruction], i1 and return a new Playground where We process ! i2: List[Instruction]! robots are swapped. ): State[Playground, (Score, Score)] = i1 matchinstructions Then we chain it with the processing of the {! case Nil if i2 == Nil of i1. i2 and tail => State.gets(_.scores)! case Nil => State[Playground, (Score, Score)] { !s => Lists of instructions are processed alternatively (s.swapRobots(), s.scores) ! }.flatMap { _ => compileInstructions(i2, i1) }! case head::tail => State[Playground, (Score, Score)] ! { s =>! val s1 = processInstruction(head)(s)! (s1.swapRobots(), s1.scores)! }.flatMap { _ => compileInstructions(i2, tail) }! } !
  • 50. Here comes the magic ! def compileInstructions(! i1: List[Instruction], ! i2: List[Instruction]! ): State[Playground, (Score, Score)] = i1 match {! case Nil if i2 == Nil => State.gets(_.scores)! case Nil => State[Playground, (Score, Score)] { s => (s.swapRobots(), s.scores) ! }.flatMap { _ => compileInstructions(i2, i1) }! case head::tail => State[Playground, (Score, Score)] ! { s =>! val s1 = processInstruction(head)(s)! (s1.swapRobots(), s1.scores)! }.flatMap { _ => compileInstructions(i2, tail) }! } !
  • 51. Using for comprehensions def getPositions(p: Playground): (Position, Position) = (p.r1.currentPosition, p.r2.currentPosition)! ! def enhanceResult(! i1: List[Instruction], ! i2: List[Instruction]): State[Playground, (String, (Position, Position))] = {! for {! scores <- compileInstructions(i1, i2)! positions <- State.gets(getPositions)! } yield (declareWinners(scores), positions)! }
  • 52. Conclusion • State Monad simplify computations on states • Use it whenever you want to manipulate states in a purely functional (parsing, caching, validation ...)
  • 53. To learn more about State Monad • Functional programming in Scala by Paul Chiusano and Rúnar Bjarnason - This book is awesome ! • State Monad keynote by Michael Pilquist - https:// speakerdeck.com/mpilquist/scalaz-state-monad • Learning scalaz by Eugene Yokota - http:// eed3si9n.com/learning-scalaz/State.html