val foo: IO[List[Int]] = List(IO.pure(100)).sequence
在哪里可以找到
sequence
方法的实现?我认为 cats.effect.IO
有一个 Traverse 类型类实现,在哪里可以找到这个实现?如果我错了,上面的foo
是如何工作的?谢谢
Traverse
没有 IO
,我相信没有,并且如果有的话与此示例无关。Traverse
代表 List
,还有一个 Applicative
代表 IO
。由于 IO
也形成了 Monad
,那么它就会委托给 IO
。
总的来说,我们知道:
def sequence[A, F[_], G[_]](fga: F[G[A]])(using Traverse[F], Applicative[G]): G[F[A]] =
traverse(fga)(identity)
trait Traverse[F[_]]:
def traverse[A, B, G[_]](fa: F[A])(f: A => G[B])(using Applicative[G]): G[F[B]]
对于
List
,traverse
的实现如下:
given Traverse[List] with
override def traverse[A, B, G[_]](fa: List[A])(f: A => G[B])(Applicative[G]): G[List[B]] =
fa.foldLeft(Appliative[G].pure(List.empty[B])) {
case (accG: G[List[B]], a: A) =>
val gb: G[B] = f(a)
Appliative[G].map2(accG, gb) {
case (acc: List[B], b: B) =>
b :: acc
}
}.map(_.reverse) // Or you could use foldRight or another more optimal strategy but that is besides the point.
我们也知道,当存在
Monad[G]
时:
trait Monad[G[_]] extends Applicative[G]:
override def map2[A, B, C](ga: G[A], gb: G[B])(f: (A, B) => C): G[C] =
for
a <- ga
b <- gb
c = f(a, b)
yield c
所以,换句话说,这只是使用 List
对
flatMaps
进行 遍历。
相关来源:
Traverse[List]
:https://github.com/typelevel/cats/blob/main/core/src/main/scala/cats/instances/list.scala#L120Async[IO]
:https://github.com/typelevel/cats-effect/blob/1ba83f03445ff1cef778c3876486c5bb2b06350a/core/shared/src/main/scala/cats/effect/IO.scala#L1920map2
对于Monad
:https://github.com/typelevel/cats/blob/47fbad764ad8026d4e9f8999c7f6233c666f0df8/core/src/main/scala/cats/FlatMap.scala#L113当然,真正的实现比我使用的实现更优化,也更复杂一些。但从概念上讲,它们是等效的。