State Candy Machine

38 views
Skip to first unread message

Glendon Klassen

unread,
May 3, 2018, 9:21:30 AM5/3/18
to scala-functional
I'm working through the chapter on the State monad and I was following pretty well until we generalized RNG to State[S, +A]. 

Now I'm playing with this code to try to figure out how it works:
object Candy {
 
def update = (i: Input) => (s: Machine) =>
   
(i, s) match {
     
case (_, Machine(_, 0, _)) => s
     
case (Coin, Machine(false, _, _)) => s
     
case (Turn, Machine(true, _, _)) => s
     
case (Coin, Machine(true, candy, coin)) =>
       
Machine(false, candy, coin + 1)
     
case (Turn, Machine(false, candy, coin)) =>
       
Machine(true, candy - 1, coin)
   
}


 
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = for {
    _
<- sequence(inputs map (modify[Machine] _ compose update))
    s
<- get
 
} yield (s.coins, s.candies)
and I want to see what's going on inside of State(Machine, (Int,Int)). How do I pull the Ints out of State and, say, print the number of coins left in the machine? I realize I'm missing something here but I've spent some time with it and I'm still stuck :(

Thanks!
gjk

pagoda_5b

unread,
May 3, 2018, 7:09:40 PM5/3/18
to scala-functional
It will help you to revisit the definition of a State[S, A] which has the shape of a function

type State[S,A] = S => (A, S)

which in our exmaple means

Machine => ((Int, Int), Machine)

that is: you give it the starting (bootstrap) value of the Machine, and the function gives you back the final Machine state, tupled with the result value (candy, coins)

To be more exact, the book creates a class wrapping the function so we have

case class State[S,A]( run: S => (A,S) )

where the function "run" has the above signature Machine => ((Int, Int), Machine)

Executing the machine means providing the needed inputs to your simulation and call "run"

val startMachine: Machine = ??? //choose an initial state
val inputs: List[Input] = ??? // decide what operations are applied to the machine

//run it
val finalState: ((Int, Int), Machine) = simulateMachine(inputs).run(startMachine)

you can pattern match to extract the tuple elements like

val ((candies, coins), finalMachine) : ((Int, Int), Machine) = simulateMachine(inputs).run(startMachine)

The simulateMachine function is only describing a sequence of mutations on a starting machine state based on inputs you give. To have results, you need to actually pass specific inputs and then run the State (which will thread all the modifications from one state to the next for you)

Glendon Klassen

unread,
May 6, 2018, 1:30:07 PM5/6/18
to scala-functional
That's very helpful. Thanks for taking the time to post!

I find I have to be taught things about 5 times before I really grasp them :S.

pagoda_5b

unread,
May 7, 2018, 5:35:38 AM5/7/18
to scala-functional
It happens to everyone, I guess ;D
Reply all
Reply to author
Forward
0 new messages