SlideShare una empresa de Scribd logo
1 de 47
Descargar para leer sin conexión
Playing with the State Monad
David Galichet	

Freelance Developer
Twitter : @dgalichet
Let’s start with a simple problem
3
2
1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 0

(A, R, A, L, A, A)

2

Score : 0

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 1

(A, R, A, L, A, A)

2

Score : 0

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 1

(A, R, A, L, A, A)

2

Score : 0

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 1

(A, R, A, L, A, A)

2

Score : 0

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 1

(A, R, A, L, A, A)

2

Score : 0

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 1

(A, R, A, L, A, A)

2

Score : 0

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 1

(A, R, A, L, A, A)

2

Score : 1

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 2

(A, R, A, L, A, A)

2

Score : 1

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 2

(A, R, A, L, A, A)

2

Score : 1

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 2

(A, R, A, L, A, A)

2

Score : 1

1
0 R1 is blocked by R2 !
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 2

(A, R, A, L, A, A)

2

Score : 1

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 2

(A, R, A, L, A, A)

2

Score : 1

1
0
0

1

2

3
A simple simulation
R1

R2

3

(A, A, R, A, A, A)
Score : 2

(A, R, A, L, A, A)

2

Score : 1

1
0
0

1

2

3
The game rules
• 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
The game rules
• 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 at 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(), s.scores) !
}.flatMap { _ => compileInstructions(i2, i1) }!
case head::tail => State[Playground, (Score, Score)] !
{ s =>!
If both i1 and i2 are empty, we return a State
val s1 = processInstruction(head)(s)!
Monad with the run method implementation :
(s1.swapRobots(), s1.scores)!
s => (s, s.scores)!
}.flatMap { _ => compileInstructions(i2, tail) }!
This will return the Playground passed in argument
}
and the score as result.
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 =>!
val s1 = processInstruction(head)(s)!
(s1.swapRobots(), s1.scores)!
If i1 is empty, we return a State Monad with a
}.flatMap { _ that compileInstructions(i2, tail) }!
run method => swap robots in Playground
}
and returns scores.
Then we chain it with the processing of
instructions for the second list.
Here comes the magic !
We process
def compileInstructions(! i1 and return a new Playground where
robots are !
i1: List[Instruction],swapped.
Then we chain it with the processing of the instructions
i2: List[Instruction]!
i2 and tail of i1.
): State[Playground, of instructions are processed alternatively {!
Lists (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(), 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/scalazstate-monad	

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

Más contenido relacionado

La actualidad más candente

Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
John De Goes
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
StackMob Inc
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
John De Goes
 

La actualidad más candente (20)

Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New Game
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
 
λ | Lenses
λ | Lensesλ | Lenses
λ | Lenses
 
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
 
Beyond Scala Lens
Beyond Scala LensBeyond Scala Lens
Beyond Scala Lens
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class Patterns
 
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...
 
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
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
 
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
 
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
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritance
 
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...
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
 
Scala intro workshop
Scala intro workshopScala intro workshop
Scala intro workshop
 
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
 

Destacado

Type class polymorphism
Type class polymorphismType class polymorphism
Type class polymorphism
Mayank Bairagi
 
전자책산업동향과 서비스 모델 (Slide Share)
전자책산업동향과 서비스 모델 (Slide Share)전자책산업동향과 서비스 모델 (Slide Share)
전자책산업동향과 서비스 모델 (Slide Share)
Joong Ho Lee
 

Destacado (20)

Type class polymorphism
Type class polymorphismType class polymorphism
Type class polymorphism
 
Building a Functional Stream in Scala
Building a Functional Stream in ScalaBuilding a Functional Stream in Scala
Building a Functional Stream in Scala
 
하스켈 프로그래밍 입문 3
하스켈 프로그래밍 입문 3하스켈 프로그래밍 입문 3
하스켈 프로그래밍 입문 3
 
mjprof: Monadic approach for JVM profiling
mjprof: Monadic approach for JVM profilingmjprof: Monadic approach for JVM profiling
mjprof: Monadic approach for JVM profiling
 
(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)
 
Pratical eff
Pratical effPratical eff
Pratical eff
 
The Eff monad, one monad to rule them all
The Eff monad, one monad to rule them allThe Eff monad, one monad to rule them all
The Eff monad, one monad to rule them all
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the Monadster
 
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
 
Real world akka recepies v3
Real world akka recepies v3Real world akka recepies v3
Real world akka recepies v3
 
Functional Programming in C# and F#
Functional Programming in C# and F#Functional Programming in C# and F#
Functional Programming in C# and F#
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monads
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-Toe
 
The monad fear
The monad fearThe monad fear
The monad fear
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
Les évolutions adaptatives
Les évolutions adaptativesLes évolutions adaptatives
Les évolutions adaptatives
 
The Coming Intelligent Digital Assistant Era and Its Impact on Online Platforms
The Coming Intelligent Digital Assistant Era and Its Impact on Online PlatformsThe Coming Intelligent Digital Assistant Era and Its Impact on Online Platforms
The Coming Intelligent Digital Assistant Era and Its Impact on Online Platforms
 

Similar a Playing with State Monad

F# at GameSys
F# at GameSysF# at GameSys
F# at GameSys
Yan Cui
 
Adventures In Data Compilation
Adventures In Data CompilationAdventures In Data Compilation
Adventures In Data Compilation
Naughty Dog
 
ACI-Webinar-3-MinMaxAlphaBetaPruning-TicTacToe.pptx
ACI-Webinar-3-MinMaxAlphaBetaPruning-TicTacToe.pptxACI-Webinar-3-MinMaxAlphaBetaPruning-TicTacToe.pptx
ACI-Webinar-3-MinMaxAlphaBetaPruning-TicTacToe.pptx
ssuser1eba67
 
Stateモナドの解説 後編
Stateモナドの解説 後編Stateモナドの解説 後編
Stateモナドの解説 後編
Masahiro Honma
 
Help with root locus homework1
Help with root locus homework1Help with root locus homework1
Help with root locus homework1
Assignmentpedia
 

Similar a Playing with State Monad (20)

F# at GameSys
F# at GameSysF# at GameSys
F# at GameSys
 
F# in the Real World (DDD EA)
F# in the Real World (DDD EA)F# in the Real World (DDD EA)
F# in the Real World (DDD EA)
 
Ch4b
Ch4bCh4b
Ch4b
 
Provenance Games
Provenance GamesProvenance Games
Provenance Games
 
Adventures In Data Compilation
Adventures In Data CompilationAdventures In Data Compilation
Adventures In Data Compilation
 
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
 
The Ring programming language version 1.10 book - Part 71 of 212
The Ring programming language version 1.10 book - Part 71 of 212The Ring programming language version 1.10 book - Part 71 of 212
The Ring programming language version 1.10 book - Part 71 of 212
 
Scaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazScaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of Scalaz
 
ACI-Webinar-3-MinMaxAlphaBetaPruning-TicTacToe.pptx
ACI-Webinar-3-MinMaxAlphaBetaPruning-TicTacToe.pptxACI-Webinar-3-MinMaxAlphaBetaPruning-TicTacToe.pptx
ACI-Webinar-3-MinMaxAlphaBetaPruning-TicTacToe.pptx
 
PUSH DOWN AUTOMATA VS TURING MACHINE
PUSH DOWN AUTOMATA VS TURING MACHINEPUSH DOWN AUTOMATA VS TURING MACHINE
PUSH DOWN AUTOMATA VS TURING MACHINE
 
12IRGeneration.pdf
12IRGeneration.pdf12IRGeneration.pdf
12IRGeneration.pdf
 
Scala kansai summit-2016
Scala kansai summit-2016Scala kansai summit-2016
Scala kansai summit-2016
 
Brief tour of psp-std
Brief tour of psp-stdBrief tour of psp-std
Brief tour of psp-std
 
Stateモナドの解説 後編
Stateモナドの解説 後編Stateモナドの解説 後編
Stateモナドの解説 後編
 
ScotRuby - Dark side of ruby
ScotRuby - Dark side of rubyScotRuby - Dark side of ruby
ScotRuby - Dark side of ruby
 
Deep RL.pdf
Deep RL.pdfDeep RL.pdf
Deep RL.pdf
 
lalr. fo engineering student those who to
lalr. fo engineering student those who tolalr. fo engineering student those who to
lalr. fo engineering student those who to
 
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
 
AI - Introduction to Markov Principles
AI - Introduction to Markov PrinciplesAI - Introduction to Markov Principles
AI - Introduction to Markov Principles
 
Help with root locus homework1
Help with root locus homework1Help with root locus homework1
Help with root locus homework1
 

Último

Último (20)

Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 

Playing with State Monad

  • 1. Playing with the State Monad David Galichet Freelance Developer Twitter : @dgalichet
  • 2. Let’s start with a simple problem 3 2 1 0 0 1 2 3
  • 3. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 0 (A, R, A, L, A, A) 2 Score : 0 1 0 0 1 2 3
  • 4. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 1 (A, R, A, L, A, A) 2 Score : 0 1 0 0 1 2 3
  • 5. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 1 (A, R, A, L, A, A) 2 Score : 0 1 0 0 1 2 3
  • 6. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 1 (A, R, A, L, A, A) 2 Score : 0 1 0 0 1 2 3
  • 7. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 1 (A, R, A, L, A, A) 2 Score : 0 1 0 0 1 2 3
  • 8. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 1 (A, R, A, L, A, A) 2 Score : 0 1 0 0 1 2 3
  • 9. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 1 (A, R, A, L, A, A) 2 Score : 1 1 0 0 1 2 3
  • 10. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 2 (A, R, A, L, A, A) 2 Score : 1 1 0 0 1 2 3
  • 11. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 2 (A, R, A, L, A, A) 2 Score : 1 1 0 0 1 2 3
  • 12. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 2 (A, R, A, L, A, A) 2 Score : 1 1 0 R1 is blocked by R2 ! 0 1 2 3
  • 13. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 2 (A, R, A, L, A, A) 2 Score : 1 1 0 0 1 2 3
  • 14. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 2 (A, R, A, L, A, A) 2 Score : 1 1 0 0 1 2 3
  • 15. A simple simulation R1 R2 3 (A, A, R, A, A, A) Score : 2 (A, R, A, L, A, A) 2 Score : 1 1 0 0 1 2 3
  • 16. The game rules • 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
  • 17. The game rules • 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
  • 18. Think about this game • It appears that we will deal with many states : • Playground with its coins • Robots with their positions and gathered coins
  • 19. 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
  • 20. 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
  • 21. 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 !
  • 22. Introducing State Monad • The aim of the state monad is to abstract over state manipulations
  • 23. 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] = ???! }
  • 24. 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 !
  • 25. 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] = ???! }
  • 26. 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)! }! }
  • 27. 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
  • 28. 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 { ... }
  • 29. 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))! }
  • 30. 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)
  • 31. 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)! }
  • 32. 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)! }
  • 33. Look at 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
  • 34. 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
  • 35. 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))! }! }
  • 36. 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))! }!
  • 37. 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)! }! }
  • 38. 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)) }! }
  • 39. 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) }! }
  • 40. 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 =>! If both i1 and i2 are empty, we return a State val s1 = processInstruction(head)(s)! Monad with the run method implementation : (s1.swapRobots(), s1.scores)! s => (s, s.scores)! }.flatMap { _ => compileInstructions(i2, tail) }! This will return the Playground passed in argument } and the score as result.
  • 41. 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 =>! val s1 = processInstruction(head)(s)! (s1.swapRobots(), s1.scores)! If i1 is empty, we return a State Monad with a }.flatMap { _ that compileInstructions(i2, tail) }! run method => swap robots in Playground } and returns scores. Then we chain it with the processing of instructions for the second list.
  • 42. Here comes the magic ! We process def compileInstructions(! i1 and return a new Playground where robots are ! i1: List[Instruction],swapped. Then we chain it with the processing of the instructions i2: List[Instruction]! i2 and tail of i1. ): State[Playground, of instructions are processed alternatively {! Lists (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) }! }
  • 43. 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) }! }
  • 44. 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)! }
  • 45. Conclusion • State Monad simplify computations on states • Use it whenever you want to manipulate states in a purely functional (parsing, caching, validation ...)
  • 46. 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/scalazstate-monad • Learning scalaz by Eugene Yokota - http:// eed3si9n.com/learning-scalaz/State.html