Я думаю, что у вас проблема в том, что вы видите эти вещи на основе их реализации, а не их типов.Рассмотрим это простое представление типов:
List[A] = Nil
| Cons head: A tail: List[A]
Option[A] = None
| Some el: A
Теперь давайте рассмотрим сгиб Option
:
fold[B] = (noneCase: => B, someCase: A => B) => B
Итак, на Option
он сводит каждый возможный случай к некоторомузначение в B
и вернуть его.Теперь давайте посмотрим на то же самое для List
:
fold[B] = (nilCase: => B, consCase: (A, List[A]) => B) => B
Заметьте, однако, что у нас есть рекурсивный вызов на List[A]
.Мы должны как-то сложить это, но мы знаем, что fold[B]
на List[A]
всегда будет возвращать B
, поэтому мы можем переписать это так:
fold[B] = (nilCase: => B, consCase: (A, B) => B) => B
Другими словами, мы заменили List[A]
на B
, потому что сворачивание всегда будет возвращать B
, учитывая сигнатуру типа fold
.Теперь давайте рассмотрим сигнатуру типа Scala (прецедент) для foldRight
:
foldRight[B](z: B)(f: (A, B) ⇒ B): B
Скажите, это вам что-то напоминает?