Scala中用于理解的Future[选项]
我有两个函数返回期货。我正试图使用一个屈服理解函数将第一个函数的修改结果输入到另一个函数中 这种方法在以下方面起作用:Scala中用于理解的Future[选项],scala,future,for-comprehension,Scala,Future,For Comprehension,我有两个函数返回期货。我正试图使用一个屈服理解函数将第一个函数的修改结果输入到另一个函数中 这种方法在以下方面起作用: val schoolFuture = for { ud <- userStore.getUserDetails(user.userId) sid = ud.right.toOption.flatMap(_.schoolId) s <- schoolStore.getSchool(sid.get) if sid.isDefined }
val schoolFuture = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- schoolStore.getSchool(sid.get) if sid.isDefined
} yield s
val schoolFuture=for{
ud(编辑以给出正确答案!)
这里的关键是未来
和选项
不要在中为
组合,因为没有正确的平面图
签名。提醒一下,对于这样的德苏加:
for ( x0 <- c0; w1 = d1; x1 <- c1 if p1; ... ; xN <- cN) yield f
c0.flatMap{ x0 =>
val w1 = d1
c1.filter(x1 => p1).flatMap{ x1 =>
... cN.map(xN => f) ...
}
}
要将一个选项
变成一个已经完成的未来
for {
ud <- userStore.getUserDetails(user.userId) // RHS is a Future[Either[...]]
sid = ud.right.toOption.flatMap(_.schoolId) // RHS is an Option[Int]
fid <- sid.map(Future.successful).getOrElse(Future.failed(new Exception)) // RHS is Future[Int]
s <- schoolStore.getSchool(fid)
} yield s
然后,突然之间,对理解的要求又变得合理了:
for {
ud <- userStore.getUserDetails(user.userId)
sid <- ud.right.toOption.flatMap(_.schoolId).future
s <- schoolStore.getSchool(sid)
} yield s
用于{
ud关于Promise[Option[a]]
的类似问题可能会有所帮助。只需用Future
代替Promise
我根据您的问题推断出getUserDetails
和getSchool
的以下类型:
getUserDetails: UserID => Future[Either[??, UserDetails]]
getSchool: SchoolID => Future[Option[School]]
由于忽略了或中的故障值,将其转换为选项
,因此实际上有两个类型为A=>Future[Option[B]]
的值
一旦你有了Future
的Monad
实例(其中可能有一个,或者你可以按照我链接的答案编写自己的),将OptionT
转换器应用于你的问题就会像这样:
for {
ud <- optionT(getUserDetails(user.userID) map (_.right.toOption))
sid <- optionT(Future.successful(ud.schoolID))
s <- optionT(getSchool(sid))
} yield s
用于{
ud如果选项[School]
为None
,您希望发生什么行为?您希望未来失败吗?有什么例外?您希望它永远不会完成吗?(听起来是个坏主意)
无论如何,for表达式中的if
子句将调用filter
方法
如果当前未来包含满足谓词的值,
新的未来也将保持这种价值。否则,结果
未来将以一种非接触式的例外而失败
但是等等:
scala> None.get
java.util.NoSuchElementException: None.get
正如您所看到的,None.get返回完全相同的内容
因此,如果定义了sid.isDefined
,那么就应该去掉,这应该会返回一个合理的结果:
val schoolFuture = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- schoolStore.getSchool(sid.get)
} yield s
val schoolFuture=for{
ud我们在Future[Option[T]]上做了一个小包装器,它的作用类似于一个monad(甚至没有人检查monad定律,但有map、flatMap、foreach、filter等等)。它的作用远不止一个异步选项
那里有很多难闻的代码,但至少作为一个例子,它可能是有用的。
顺便说一句:有很多开放性问题(例如)它更容易使用https://github.com/qifun/stateless-future
或https://github.com/scala/async
要执行A-Normal-Form
转换。这给了我一个编译错误。发现:scala.concurrent.Future[Option[com.authorpub.userservice.School]]必需:选项[?]s您能解释一下您所有的类型是什么吗?考虑到您还没有发布完整的工作代码,有点难说。未来是什么,工作代码中的选项是什么?如果您这样做,您可以让Scala 2.10打印出表达式的类型:import Scala.reflect.runtime.universe.\u;def typeme[A:TypeTag](A:A)={println(隐式[TypeTag[A]]);A}
然后将表达式包装在typeme
中,例如sid=typeme(ud.right.toOption.flatMap(u.schoolID))
。有人未经评论就投了反对票。这不是很有用。现在的答案有什么问题吗?我更喜欢本·詹姆斯的答案。虽然Scalaz、Monads和所有这些东西让很多人感到害怕,但事实上这些概念非常简单。Scalaz已经有了解决问题所需的所有抽象。相反,这个answer引入了一个新概念OptionIsFuture
,我认为它类似于monad transformer。诚然,scalaz让我有点害怕,我仍然有办法继续学习。这解决了我认为可以解决的问题。谢谢!谢谢你的回答,但是到scalaz contrib库的链接断开了。你不需要dscalaz contrib不再
,因为Monad的未来实例现在由scalaz自己通过混合FutureInstances
特性来提供。对于不需要scalaz;)的解决方案,+1
for {
ud <- userStore.getUserDetails(user.userId)
sid <- ud.right.toOption.flatMap(_.schoolId).future
s <- schoolStore.getSchool(sid)
} yield s
getUserDetails: UserID => Future[Either[??, UserDetails]]
getSchool: SchoolID => Future[Option[School]]
for {
ud <- optionT(getUserDetails(user.userID) map (_.right.toOption))
sid <- optionT(Future.successful(ud.schoolID))
s <- optionT(getSchool(sid))
} yield s
scala> None.get
java.util.NoSuchElementException: None.get
val schoolFuture = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- schoolStore.getSchool(sid.get)
} yield s