在理解中结合列表、未来和选项 - scalaz
Combining List, Future and Option in for-comprehension - scalaz
我遇到了以下问题:
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
我想让这段代码工作(我想每个人都理解这个想法,因为我添加了类型)。
"to work" 我的意思是,我希望继续使用 for-comprehension 结构并最终实现预期的类型。我知道有 "ugly" 种方法可以做到这一点,但我想学习如何纯粹地做到这一点 :)
当我阅读互联网时,我得出的结论是我的问题可以通过 monad 转换器和 scalaz 解决。不幸的是,我找不到一个例子来帮助更好地理解我应该如何进行。
目前我已经尝试过 scalaz 和 Eff monad 库,但我想我仍然不明白它是如何工作的,因为我无法解决我的问题。
如有任何帮助,我将不胜感激。
编辑:它应该是序列的未来,也关于 "whatever" 我把它作为函数的参数,很抱歉误导你
您可以使用 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.: 既然你从一个future开始,你就不能return一个Seq[(T,S)],你只能有一个future。如果你想阻止并得到结果,你必须调用Await.result。
for
理解的问题在于它不是某种神奇的单子 "unwrapper",它只是 map
、flatMap
和 [=16= 的序列].
如您所知,map
和 flatMap
仅在 "inner" 类型上运行,而 "outer" 类型的 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 提到,如果不显式调用 Await
.
,就无法摆脱 Future
我遇到了以下问题:
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
我想让这段代码工作(我想每个人都理解这个想法,因为我添加了类型)。
"to work" 我的意思是,我希望继续使用 for-comprehension 结构并最终实现预期的类型。我知道有 "ugly" 种方法可以做到这一点,但我想学习如何纯粹地做到这一点 :)
当我阅读互联网时,我得出的结论是我的问题可以通过 monad 转换器和 scalaz 解决。不幸的是,我找不到一个例子来帮助更好地理解我应该如何进行。
目前我已经尝试过 scalaz 和 Eff monad 库,但我想我仍然不明白它是如何工作的,因为我无法解决我的问题。
如有任何帮助,我将不胜感激。
编辑:它应该是序列的未来,也关于 "whatever" 我把它作为函数的参数,很抱歉误导你
您可以使用 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.: 既然你从一个future开始,你就不能return一个Seq[(T,S)],你只能有一个future。如果你想阻止并得到结果,你必须调用Await.result。
for
理解的问题在于它不是某种神奇的单子 "unwrapper",它只是 map
、flatMap
和 [=16= 的序列].
如您所知,map
和 flatMap
仅在 "inner" 类型上运行,而 "outer" 类型的 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 提到,如果不显式调用 Await
.
Future