考虑retrieveUser
的签名,其中检索不存在的用户不会被建模为错误,也就是说,它被建模为Future[Right[None]]
:
def retrieveUser(email: String): Future[Either[Error, Option[User]]]
是否存在monad变换器MT
,以便我们可以写
(for {
user <- MT(retrieveUser(oldEmail))
_ <- MT(updateUser(user.setEmail(newEmail)))
} {}).run
使用EitherT
我能做的最好的事情如下:
EitherT(retrieveUser(oldEmail)).flatMap {
case Some(user) =>
EitherT(updateUser(user.setEmail(newEmail)))
case None =>
EitherT.right(Future.successful({}))
}.run
问题在于,EitherT(retrieveUser(email))
上的映射会产生Option[User]
,而不是取消装箱User
,从而打破了理解。
答案 0 :(得分:3)
我假设参数的顺序与EitherT
form Scala Cats中的相同:EitherT[F[_], A, B]
基本上只是F[Either[A, B]]
的包装。
同样,OptionT[F, A]
是F[Option[A]]
的包装。
因此,
OptionT[EitherT[Future, Error, ?], A]
是
的包装EitherT[Future, Error, Option[A]]
又是
的包装Future[Either[Error, Option[A]]]
因此,
OptionT[EitherT[Future, Error, ?], User](
EitherT[Future, Error, Option[User]](retrieveUser(oldEmail))
)
应该使用the non/kind-projector
)进行类型检查,并且使用-Ypartial-unification
类型也应该自动推断,因此您可以尝试使用
OptionT(EitherT(retrieveUser(oldEmail))
在for-comprehensions里面。