Монадный трансформатор для будущего [Либо [Ошибка, Опция [Пользователь]]] - PullRequest
0 голосов
/ 05 мая 2018

Рассмотрим подпись retrieveUser, когда извлечение несуществующего пользователя не смоделировано как ошибка, то есть смоделировано как Future[Right[None]]:

def retrieveUser(email: String): Future[Either[Error, Option[User]]]

Существует ли монадный преобразователь 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, что нарушает понимание.

1 Ответ

0 голосов
/ 05 мая 2018

Я предполагаю, что порядок параметров такой же, как в EitherT форме 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))

внутри для понимания.

...