4

Exercise 6.8, Chiusano and Bjarnason, Functional Programming in Scala, p. 87 asks how one might implement flatMap() for the following trait:

trait RNG {
  def nextInt: (Int, RNG)
}

type Rand[+A] = RNG => (A, RNG)

The answer key gives the following solution:

def flatMap[A,B](f: Rand[A])(g: A => Rand[B]): Rand[B] =
rng => {
  val (a, r1) = f(rng)
  g(a)(r1) // We pass the new state along
}

Stackoverflow provides many answers to flatMap()/monad questions, but none which for me answered my questions regarding the next to last line of code.

I do not understand the syntax of the line

g(a)(r1)

(1) I do not understand how g(a)(r1) evaluates. What syntactic function is served by (r1)? The line does not exemplify currying, I do not believe, since g takes only one argument: A. (2) If g(a) will already return the type Rand[B], then why does not the line end here? (3) what is the relation between the Rand[B] returned by g(a) and the second set of parentheses: (r1)? (4) if the return type of this implementation of flatMap() is Rand[B], which is equal to RNG => (A, RNG), how are the enclosing parentheses to the right of the arrow generated? If I had to guess I would say they are generated by the evaluation, (r1), but I do not really understand this code given my questions 1 through 3.

Ben Weaver
  • 960
  • 1
  • 8
  • 18

1 Answers1

4

Remember that we're calling f and g inside a new anonymous function, as indicated by the line

rng => { ... }

g returns a Rand[B] when given an A, so g(a) evaluates to a function from RNG to (A, RNG).

So g(a) returns a function expecting an RNG as its argument, we can then call this with our r1, which is of type RNG.

The result of the call is (B, RNG). Now since the flatMap signature expects you to return a Rand[B] which is the same as RNG => (B, RNG) and we return (B, RNG) inside our function, it exactly matches the signature.

Luka Jacobowitz
  • 22,795
  • 5
  • 39
  • 57
  • 1
    Thanks, Luka, this is great. Makes perfect sense. The key knowledge for me is to learn that (r1) indeed represents the call on the function returned by g(a). I guess it is like curry syntax: f[A,B,C](a)(b) : a => (b => c), in reverse. – Ben Weaver Jun 06 '17 at 19:37