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

Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 

Recently uploaded (20)

Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 

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