未来的Monad转换器[Either [Error,Option [User]]]

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,这会破坏人们的理解力。

And*_*kin 3

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 理解里面。