Понимание функции curried, переданной в fold

#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. Спасибо за ваш ответ. Я применил изменения.