我有以下问题:
val sth: Future[Seq[T, S]] = for {
x <- whatever: Future[List[T]]
y <- x: List[T]
z <- f(y): Future[Option[S]]
n <- z: Option[S]
} yield y: T -> n: S
我想让这段代码工作(我想每个人都理解这个想法,因为我添加了类型)。
通过“工作”我的意思是,我希望保持for-comprehension结构并最终实现预期的类型。我知道有“丑陋”的方法可以做到这一点,但我想学习如何做到这一点:)
当我读到互联网时,我得出结论,我的问题可能会被monad变形金刚和scalaz解决。不幸的是,我找不到一个例子来帮助我更好地理解我应该如何进行。
目前我已经尝试了scalaz和Eff monad libs,但我想我仍然不明白它是如何工作的,因为我无法解决我的问题。
我将不胜感激任何帮助。
编辑:它应该是序列的未来,也是关于“什么”我得到它作为函数的参数,抱歉误导你
你可以使用scalaz ListT monad transformer做你需要的东西
object Test {
import scalaz._
import ListT._
type T = String
type S = Int
val whatever: Future[List[T]] = ??? // you get this somewhere
def f(y: T): Future[Option[S]] = ??? // function that returns future of option
val sth: Future[List[(T, S)]] = (for {
y <- listT(whatever)
// you cannot mix list and option, but you can convert the option to a list of 1 item
n <- listT(f(y).map(_.toList))
} yield y -> n).run
}
N.B。:既然你从未来开始,你就不能返回Seq [(T,S)],你只能拥有未来。如果要阻止并获得结果,则必须调用Await.result。
for
理解的问题在于它不是某种神奇的monadic“unwrapper”,它只是map
,flatMap
和filter
的序列。
你可能知道map
和flatMap
仅在“内部”类型上运作,使“外部”类型的monad保持不变。这意味着你不能这样做:
for {
x <- whatever: Future[List[T]]
y <- x: List[T]
} yield y
在单个for
内。相反,你可以做这样的事情:
for (x <- whatever: Future[List[T]])
yield for (y <- x: List[T]) yield y
哪个看起来有点难看。
回到你的情况,我更容易使用map
和flatMap
明确地编写整个转换,因为它为你提供了更大的可见性和控制:
whatever.flatMap {
x: List[T] =>
Future.sequence(x.map {
y: T => f(y).map(y -> _)
}).map(_.collect {
case (y, Some(n)) => y -> n
})
}
另外,@ trustnoone提到,你不能在没有明确调用Future
的情况下摆脱Await
。