flatMap() 的状态转换实现

Implementation of flatMap() for State transition

练习 6.8,Chiusano 和 Bjarnason,Scala 中的函数式编程,p. 87 询问如何为以下特征实现 flatMap():

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

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

答案关键给出了以下解决方案:

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
}

Whosebug 为 flatMap()/monad 问题提供了很多答案,但是 none 它回答了我关于倒数第二行代码的问题。

我不明白该行的语法

g(a)(r1)

(1) 我不明白 g(a)(r1) 是如何计算的。 (r1) 提供什么句法功能?我不相信该行并没有举例说明柯里化,因为 g 只接受一个参数:A。 (2) 如果 g(a) 已经 return 类型 Rand[B],那么为什么行不在这里结束? (3) g(a)求出的Rand[B] return和第二组括号:(r1)是什么关系? (4)如果flatMap()的这个实现的return类型是Rand[B],等于RNG => (A, RNG),箭头右边的括号是怎么生成的?如果我不得不猜测,我会说它们是由评估生成的,(r1),但鉴于我的问题 1 到 3,我并不真正理解这段代码。

请记住,我们在一个新的匿名函数中调用 fg,如行

所示
rng => { ... }

g returns a Rand[B] 当给定 A 时,因此 g(a) 计算为从 RNG 到 [=18 的函数=].

所以 g(a) return 是一个需要 RNG 作为其参数的函数,然后我们可以用我们的 r1 调用它,它的类型是 RNG.

调用的结果是(B, RNG)。现在,由于 flatMap 签名希望您 return 一个 Rand[B]RNG => (B, RNG) 相同,而我们在函数中 return (B, RNG),它与签名完全匹配。