Code here: https://github.com/fpinscala/fpinscala/blob/master/answers/src/main/scala/fpinscala/state/State.scala
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = for {
_ <- sequence(inputs map ((modify[Machine] _) compose update))
s <- get
} yield (s.coins, s.candies)
I don't understand how the second line s <- get
works in this for-comprehension.
As far as I can see, the first line creates a State[Machine, List[Unit]] and flatMap throws away the List[Unit] with _.
Subsequently, in the second line, I dont get understand how get
is being applied to the Machine
created in the first line. How does the Machine
get passed along?
EDIT:
Thanks jwvh and Markus Appel for the replies, I get now that get
is a method with no parameters that returns a State[S, S]
.
Now I think I get it but please correct me if i'm wrong. First, I expanded the for-comprehension as per below.
sequence(inputs map ((modify[Machine] _) compose update))
.flatMap(_ => get
.map(s => (s.coins, s.candies))
get.map(s => (s.coins, s.candies)
can be substituted with State(s => (s, s)).map(s => (s.coins, s.candies)
and eventually State(s => (s, (s.coins, s.candies)))
sequence(inputs map ((modify[Machine] _) compose update))
.flatMap(_ => State(s => (s, (s.coins, s.candies))))
Substituting the outer sequence(inputs map ((modify[Machine] _) compose update)).flatMap
with the definition, I see
State(s => {
val (a, s1) = sequence(inputs map ((modify[Machine] _) compose update)).run(s)
f(a).run(s1)
})
Now I substitute f(a)
with an evaluation of _ => State(s => (s, (s.coins, s.candies)))
State(s => {
val (a, s1) = sequence(inputs map ((modify[Machine] _) compose update)).run(s)
State(s => (s, (s.coins, s.candies))).run(s1)
})
Essentially, the sequence(inputs map ((modify[Machine] _) compose update))
produces a Machine
in the final state after executing the list of inputs and produces an output of type State[Machine, List[Unit]]
. But the actual Machine
within this State is not passed along explicitly. Rather it is passed along implicitly by flatMap
definition when it calls State(s => (s, (s.coins, s.candies))).run(s1)
via .run(s1)
.
As @jwvh already pointed out, get
is a method defined in object State
.
The get
-method is neither applied to any Machine
nor is a Machine
used as parameter, because the function has the following signature:
def get[S]: State[S, S] = State(s => (s, s))
This means get
has no parameters and the return type is State[S, S]
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With