Mar*_*lic 5 monads scala monad-transformers scalaz
请考虑以下特征:retrieveUser在检索不存在的用户时,其签名未建模为错误,也就是说,其建模为Future[Right[None]]:
def retrieveUser(email: String): Future[Either[Error, Option[User]]]
Run Code Online (Sandbox Code Playgroud)
是否存在一个monad变压器MT,以便我们可以编写
(for {
user <- MT(retrieveUser(oldEmail))
_ <- MT(updateUser(user.setEmail(newEmail)))
} {}).run
Run Code Online (Sandbox Code Playgroud)
使用EitherT我所能做的最好的是以下情况:
EitherT(retrieveUser(oldEmail)).flatMap {
case Some(user) =>
EitherT(updateUser(user.setEmail(newEmail)))
case None =>
EitherT.right(Future.successful({}))
}.run
Run Code Online (Sandbox Code Playgroud)
问题在于,映射到会EitherT(retrieveUser(email))产生Option[User],而不是unboxed User,这会破坏人们的理解力。
EitherT我假设参数的顺序与Scala Cats 形式相同: anEitherT[F[_], A, B]本质上只是一个包装器F[Either[A, B]]。
同样,OptionT[F, A]是 的包装器F[Option[A]]。
因此,
OptionT[EitherT[Future, Error, ?], A]
Run Code Online (Sandbox Code Playgroud)
是一个包装器
EitherT[Future, Error, Option[A]]
Run Code Online (Sandbox Code Playgroud)
这又是一个包装器
Future[Either[Error, Option[A]]]
Run Code Online (Sandbox Code Playgroud)
所以,
OptionT[EitherT[Future, Error, ?], User](
EitherT[Future, Error, Option[User]](retrieveUser(oldEmail))
)
Run Code Online (Sandbox Code Playgroud)
应该进行类型检查(with the non/kind-projector),并且-Ypartial-unification类型也应该自动推断,所以你可以尝试使用
OptionT(EitherT(retrieveUser(oldEmail))
Run Code Online (Sandbox Code Playgroud)
在 for 理解里面。