Реализация flatMap() для перехода между состояниями
Упражнение 6.8, Кьюзано и Бьярнасон, Функциональное программирование в Scala, с. 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
}
Stackru предоставляет много ответов на вопросы flatMap()/monad, но ни один из них для меня не ответил на мои вопросы, касающиеся следующей или последней строки кода.
Я не понимаю синтаксис строки
g(a)(r1)
(1) Я не понимаю, как оценивает g(a)(r1). Какой синтаксической функции служит (r1)? Строка не является примером каррирования, я не верю, поскольку g принимает только один аргумент: A. (2) Если g (a) уже вернет тип Rand[B], то почему строка здесь не заканчивается? (3) какова связь между Rand[B], возвращаемым g (a), и вторым набором скобок: (r1)? (4) если возвращаемым типом этой реализации flatMap() является Rand[B], который равен RNG => (A, RNG), как генерируются закрывающие скобки справа от стрелки? Если бы мне пришлось угадывать, я бы сказал, что они генерируются оценкой (r1), но я не совсем понимаю этот код, учитывая мои вопросы с 1 по 3.
1 ответ
Помните, что мы звоним f
а также g
внутри новой анонимной функции, как указано в строке
rng => { ... }
g
возвращает Rand[B]
когда дали A
, так g(a)
оценивает функцию от RNG
в (A, RNG)
,
Так g(a)
возвращает функцию, ожидающую RNG
в качестве аргумента, мы можем назвать это с нашими r1
, который имеет тип RNG
,
Результат звонка (B, RNG)
, Теперь, так как flatMap
подпись ожидает от вас возврата Rand[B]
который так же, как RNG => (B, RNG)
и мы вернемся (B, RNG)
внутри нашей функции он точно соответствует сигнатуре.