Future[Either[Error, Option[User]]] 的 Monad 转换器
Monad transformer for Future[Either[Error, Option[User]]]
考虑 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
,这会破坏 for-comprehension。
我假设参数的顺序与 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 里面。
考虑 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
,这会破坏 for-comprehension。
我假设参数的顺序与 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 里面。