列出[OptionT [Future,Int]]到OptionT [Future,List [A]]

时间:2015-01-28 11:12:33

标签: scala scalaz monad-transformers

我使用异步计算构建List Int来检索元素:

(1 to n).map(anAsyncThingy).toList

其中anAsyncThingy返回OptionT[Future, Int]

因此结果为List[OptionT[Future, Int]]

我现在想要的是OptionT[Future, List[A]]

到目前为止,这是我最好的尝试(我将添加一些存根,以便它可以在REPL中运行)

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

def anAsyncThingy(x: Int): OptionT[Future, Int] = x.point[Future].liftM[OptionT]

val res = OptionT {
  Future.sequence {
    (1 to 3).map(anAsyncThingy(_).run).toList
  }.map(_.sequence)
}
res.map(println) // List(1, 2, 3)

上述工作符合预期,但我觉得使用适当的scalaz构造有很大的改进空间,而不是从monad transfomers跳出来。

如何以更直接的方式获得相同的结果?

1 个答案:

答案 0 :(得分:4)

经过一些实验后,我自己找到了答案:

val res = (1 to 3).map(anAsyncThingy).toList.sequenceU
res.map(println) // List(1, 2, 3)

是的scalaz!

顺便说一下,sequenceU需要sequence而不是OptionT[M, A] ,因为scala不够智能,无法确定何时

M

如果您修改了类型参数(例如FutureOptionT[Future, A]

M[_]

它的形状为M[_, _]

编译器一直认为它有sequenceU形状,除非用勺子(带有讨厌的lambda)

以下是scalaz Unapply开始使用sequence ∘ map ≡ traverse解决此问题的方法。有关该主题的更多信息here

更新

根据phadej的评论traverseU,所以使用(1 to 3).toList.traverseU(anAsyncThingy) 可以更加简洁:

sequence

sequenceU vs traverse的相同想法当然适用于traverseU vs {{1}}。