#scala #fold #monoids
#scala #fold #моноиды
Вопрос:
У меня возникли проблемы с пониманием этого кода из книги FP в Scala. Вот код:
trait Monoid[A] {
def op(a1: A, a2: A): A
def zero: A
}
def endoMonoid[A]: Monoid[A => A] = new Monoid[A => A] {
def op(f: A => A, g: A => A) = f compose g
val zero = (a: A) => a
}
def foldMap[A, B](as: List[A], m: Monoid[B])(f: A => B): B =
as.foldLeft(m.zero)((b, a) => m.op(b, f(a)))
// The function type `(A, B) => B`, when curried, is `A => (B => B)`.
// And of course, `B => B` is a monoid for any `B` (via function composition).
def foldRight[A, B](as: List[A])(z: B)(f: (A, B) => B): B =
foldMap(as, endoMonoid[B])(f.curried)(z)
foldMap
ожидает функцию f: A => B
.
В foldRight
, когда f
у вас есть curried A => (B => B)
, так что, я полагаю, f.curried
работает, потому что это то же самое, что (A => B => B)
, so foldRight
передает foldMap
то, что он ожидает (функция с типом A => B
), затем, что происходит дальше, это то, что foldMap
вызывается и возвращает функцию B => B
, и вот тогда z
вступает в игру в (f.curried)(z)
вы вызываете функцию B => B
с аргументом z
, чтобы получить окончательный B
.
Я прав? для меня немного сложно рассуждать об этом коде.
ПРИМЕЧАНИЕ: Вот scalafiddle, если вы хотите поиграть с ней.
Ответ №1:
Ну, вы кажетесь мне в основном всеобъемлющим. Тем не менее, я бы прояснил некоторые моменты:
- Я бы предпочел сказать «так что, я полагаю,
f.curried
работает, потому чтоA => (B => B)
это то же самое, что(A => B => B)
» (это здесь неоднозначно, и вы говорите оf.curried
типе результата в основном, а не сz
) - Я бы предпочел поставить точку вместо запятой здесь: «
foldMap
ожидает функцию f: A => B . В foldRight, … » и почти везде еще. Более короткие фразы, более четкое объяснение. - что может быть ошибкой (и что вас смущает?), Так это то, что
(f.curried)(z)
не работает само по себе и не вызывается послеfoldMap(as, endoMonoid[B])
. Она вызывается первой,foldMap(as, endoMonoid[B])(f.curried)
а затем(z)
. Первый возвращаетB => B
и вызывается со вторым возвратомB
.
Комментарии:
1. Но я явно не знаю, как грубо объяснить, почему
B => B
может быть ассимилировано какB
, вызвавfoldMap
таким образом:foldMap(as, endoMonoid[B])(f.curried)
. Я думаю, это потому, чтоA => (B => B)
это супертипA => B
, аB => B
это подтипB
. Если это то, что вам непонятно, было бы лучше подождать кого-то, кто знает, как объяснить этот момент.2. Спасибо за ваш ответ. Я применил изменения.