了解 ScalaZ 中的 FoldLeft
Understanding FoldLeft in ScalaZ
我正在阅读一些关于 ScalaZ
的文章,但对理解它有疑问。在这个 article 中,我们泛化了 sum 函数,以抽象出要求和的类型。
def sum[T](xs: List[T])(implicit m: Monoid[T]) = //...
哪里
trait Monoid[A]定义如下:
trait Monoid[A] {
def mappend(a1: A, a2: A): A
def mzero: A
}
是的,这很清楚。这里的 Monoid 对应于它在列表上抽象的 algebraic monoid structure. Now in this article 。为此,我们定义了以下特征:
trait FoldLeft[F[_]] {
def foldLeft[A, B](xs: F[A], b: B, f: (B, A) => B): B
}
object FoldLeft {
implicit val FoldLeftList: FoldLeft[List] = new FoldLeft[List] {
def foldLeft[A, B](xs: List[A], b: B, f: (B, A) => B) = xs.foldLeft(b)(f)
}
}
所以现在我们可以定义求和函数如下:
def sum[M[_]: FoldLeft, A: Monoid](xs: M[A]): A = {
val m = implicitly[Monoid[A]]
val fl = implicitly[FoldLeft[M]]
fl.foldLeft(xs, m.mzero, m.mappend)
}
我不是理论类专家,但对我来说它看起来像 Applicative functor。那是对的吗?我们能否提供与类别理论的这种相似性。
Applicative functor is a type class with two operations: A => F[A]
and F[A => B] => F[A] => F[B]
. None of operations you mentioned has such signature. FoldLeft
is more like Foldable. It's a different type class, a parent of Traversable(又名 Traverse
)。并且 Traversable
与 Applicative
相关联。
trait Functor[F[_]] {
def fmap[A, B](f: A => B)(fa: F[A]): F[B]
}
trait Applicative[F[_]] extends Functor[F] {
def pure[A](a: A): F[A]
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
override def fmap[A, B](f: A => B)(fa: F[A]): F[B] = ap(pure(f))(fa)
}
trait Foldable[T[_]] {
def foldr[A, B](op: A => B => B)(seed: B)(ta: T[A]): B =
(foldMap(op)(ta) _)(seed)
def foldMap[A, M](f: A => M)(ta: T[A])(implicit monoid: Monoid[M]): M =
foldr[A, M](a => m => monoid.append(f(a), m))(monoid.empty)(ta)
}
trait Traversable[T[_]] extends Functor[T] with Foldable[T] {
def traverse[F[_]: Applicative, A, B](k: A => F[B])(ta: T[A]): F[T[B]] =
sequence[F, B](fmap[A, F[B]](k)(ta))
def sequence[F[_]: Applicative, A](tfa: T[F[A]]): F[T[A]] =
traverse[F, F[A], A](fa => fa)(tfa)
override def fmap[A, B](f: A => B)(ta: T[A]): T[B] = traverse[Id, A, B](f)(ta)
override def foldr[A, B](op: A => B => B)(seed: B)(ta: T[A]): B =
(traverse[Const[B => B]#λ, A, B](op)(ta) _)(seed)
override def foldMap[A, M: Monoid](f: A => M)(ta: T[A]): M =
traverse[Const[M]#λ, A, M](f)(ta)
}
type Id[A] = A
trait Const[C] {
type λ[A] = C
}
Type class Functor
意味着你有一个 "container" F[_]
并且你知道如何在这个容器中应用函数 f: A => B
。键入 class Applicative
意味着您知道如何将值 a: A
打包到此容器中以及如何将 "function" F[A => B]
应用于 "value" F[A]
。 Foldable
表示您知道如何使用二进制操作 A => B => B
和起始值 B
以及接收结果 B
来折叠您的容器。 Traversable
意味着你知道如何在每个 "node".
中遍历容器执行应用效果 A => F[B]
我正在阅读一些关于 ScalaZ
的文章,但对理解它有疑问。在这个 article 中,我们泛化了 sum 函数,以抽象出要求和的类型。
def sum[T](xs: List[T])(implicit m: Monoid[T]) = //...
哪里
trait Monoid[A]定义如下:
trait Monoid[A] {
def mappend(a1: A, a2: A): A
def mzero: A
}
是的,这很清楚。这里的 Monoid 对应于它在列表上抽象的 algebraic monoid structure. Now in this article 。为此,我们定义了以下特征:
trait FoldLeft[F[_]] {
def foldLeft[A, B](xs: F[A], b: B, f: (B, A) => B): B
}
object FoldLeft {
implicit val FoldLeftList: FoldLeft[List] = new FoldLeft[List] {
def foldLeft[A, B](xs: List[A], b: B, f: (B, A) => B) = xs.foldLeft(b)(f)
}
}
所以现在我们可以定义求和函数如下:
def sum[M[_]: FoldLeft, A: Monoid](xs: M[A]): A = {
val m = implicitly[Monoid[A]]
val fl = implicitly[FoldLeft[M]]
fl.foldLeft(xs, m.mzero, m.mappend)
}
我不是理论类专家,但对我来说它看起来像 Applicative functor。那是对的吗?我们能否提供与类别理论的这种相似性。
Applicative functor is a type class with two operations: A => F[A]
and F[A => B] => F[A] => F[B]
. None of operations you mentioned has such signature. FoldLeft
is more like Foldable. It's a different type class, a parent of Traversable(又名 Traverse
)。并且 Traversable
与 Applicative
相关联。
trait Functor[F[_]] {
def fmap[A, B](f: A => B)(fa: F[A]): F[B]
}
trait Applicative[F[_]] extends Functor[F] {
def pure[A](a: A): F[A]
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
override def fmap[A, B](f: A => B)(fa: F[A]): F[B] = ap(pure(f))(fa)
}
trait Foldable[T[_]] {
def foldr[A, B](op: A => B => B)(seed: B)(ta: T[A]): B =
(foldMap(op)(ta) _)(seed)
def foldMap[A, M](f: A => M)(ta: T[A])(implicit monoid: Monoid[M]): M =
foldr[A, M](a => m => monoid.append(f(a), m))(monoid.empty)(ta)
}
trait Traversable[T[_]] extends Functor[T] with Foldable[T] {
def traverse[F[_]: Applicative, A, B](k: A => F[B])(ta: T[A]): F[T[B]] =
sequence[F, B](fmap[A, F[B]](k)(ta))
def sequence[F[_]: Applicative, A](tfa: T[F[A]]): F[T[A]] =
traverse[F, F[A], A](fa => fa)(tfa)
override def fmap[A, B](f: A => B)(ta: T[A]): T[B] = traverse[Id, A, B](f)(ta)
override def foldr[A, B](op: A => B => B)(seed: B)(ta: T[A]): B =
(traverse[Const[B => B]#λ, A, B](op)(ta) _)(seed)
override def foldMap[A, M: Monoid](f: A => M)(ta: T[A]): M =
traverse[Const[M]#λ, A, M](f)(ta)
}
type Id[A] = A
trait Const[C] {
type λ[A] = C
}
Type class Functor
意味着你有一个 "container" F[_]
并且你知道如何在这个容器中应用函数 f: A => B
。键入 class Applicative
意味着您知道如何将值 a: A
打包到此容器中以及如何将 "function" F[A => B]
应用于 "value" F[A]
。 Foldable
表示您知道如何使用二进制操作 A => B => B
和起始值 B
以及接收结果 B
来折叠您的容器。 Traversable
意味着你知道如何在每个 "node".
A => F[B]