answerkey/monoids/12.answer.md
trait Foldable[F[_]]:
import Monoid.{endoMonoid, dual}
extension [A](as: F[A])
def foldRight[B](acc: B)(f: (A, B) => B): B =
as.foldMap(f.curried)(using endoMonoid[B])(acc)
def foldLeft[B](acc: B)(f: (B, A) => B): B =
as.foldMap(a => b => f(b, a))(using dual(endoMonoid[B]))(acc)
def foldMap[B](f: A => B)(using mb: Monoid[B]): B =
as.foldRight(mb.empty)((a, b) => mb.combine(f(a), b))
def combineAll(using ma: Monoid[A]): A =
as.foldLeft(ma.empty)(ma.combine)
object Foldable:
given Foldable[List] with
extension [A](as: List[A])
override def foldRight[B](acc: B)(f: (A, B) => B) =
as.foldRight(acc)(f)
override def foldLeft[B](acc: B)(f: (B, A) => B) =
as.foldLeft(acc)(f)
given Foldable[IndexedSeq] with
extension [A](as: IndexedSeq[A])
override def foldRight[B](acc: B)(f: (A, B) => B) =
as.foldRight(acc)(f)
override def foldLeft[B](acc: B)(f: (B, A) => B) =
as.foldLeft(acc)(f)
override def foldMap[B](f: A => B)(using mb: Monoid[B]): B =
Monoid.foldMapV(as, mb)(f)
given Foldable[LazyList] with
extension [A](as: LazyList[A])
override def foldRight[B](acc: B)(f: (A, B) => B) =
as.foldRight(acc)(f)
override def foldLeft[B](acc: B)(f: (B, A) => B) =
as.foldLeft(acc)(f)