我使用异步计算构建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跳出来。
如何以更直接的方式获得相同的结果?
答案 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
如果您修改了类型参数(例如Future
到OptionT[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}}。