Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional Programing in Scala Exercise 6.11. How does this for-comprehension work?

Tags:

scala

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).

like image 807
Yarnspinner Avatar asked Nov 06 '22 12:11

Yarnspinner


1 Answers

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].

like image 178
Markus Appel Avatar answered Dec 03 '22 09:12

Markus Appel