如何在List [F [G [A]]]上运行序列得到F [G [List [A]]]

时间:2014-10-02 14:54:04

标签: scala scalaz

是否可以很好地将List[F[G[A]]]转换为F[G[List[A]]]

我可以通过以下方式在Scalaz中执行此操作:

val x: List[Future[Option[Int]]] = ???
val transformed: Future[Option[List[Int]]] = x.sequenceU.map(_.sequenceU)

我只是想知道是否有更好的方法来做这个而不是.sequenceU.map(_.sequenceU)也许使用monad变换器?我确实尝试了这一点,没有太多运气。

2 个答案:

答案 0 :(得分:5)

如果你想避免嵌套测序,Monad变换器就是你的选择。在这种情况下,您需要OptionT[Future, A](相当于Future[Option[A]]):

import scalaz._, Scalaz._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

val xs = List(OptionT(Future(some(1))), OptionT(Future(some(2))))
val ys = OptionT(Future(none[Int])) :: xs

val sequencedXs: Future[Option[List[Int]]] = xs.sequenceU.run
val sequencedYs: Future[Option[List[Int]]] = ys.sequenceU.run

然后:

scala> sequencedXs.foreach(println)
Some(List(1, 2))

scala> sequencedYs.foreach(println)
None

正如所料。

答案 1 :(得分:0)

我已经意识到虽然monad变换器在这里非常棒,但我可以利用应用程序的组成:

def transform[F[_], G[_], A](list: List[F[G[A]]])(implicit af: Applicative[F], ao: Applicative[G]): F[G[List[A]]] = {
  type λ[α] = F[G[α]]
  implicit val applicative: Applicative[λ] = af compose ao
  list.sequence[λ, A]
}
val lfo:    List[Future[Option[Int]]] = List(Future(1.some), Future(2.some))
val future: Future[Option[List[Int]]] = transform(lfo)

然后:

scala> future.foreach(println)
Some(List(1, 2))