I was coding a for comprehension, and wondered something:
def updateUserStats(user: User): Either[Error,User] = for {
stampleCount <- stampleRepository.
In a for-comprehension all monads have to be of the same kind. That means you can not mix RightProjection
and Option
, because the output has to be an Either
. This is because the for-comprehension gets translated to a nested flatMap/map construct. Your example would look like this:
def updateUserStats(user: User): Either[Error,User] =
stampleRepository.getStampleCount(user).right.flatMap { stampleCount =>
Some(copyUserWithStats(user,stampleCount)).flatMap { userUpdated =>
userService.update(userUpdated).right.map { userSaved =>
userSaved
}
}
}
If we now look at the signature of RightProjection.flatMap
, which is def
flatMap[AA >: A, Y](f: (B) ⇒ Either[AA, Y]): Either[AA, Y]
, we see, that the result has to be an Either
, but flatMap
of Option
has the signature flatMap[B](f: (A) ⇒ Option[B]): Option[B]
. It returns an Option
and there is no sane way to translate an Option
to an Either
.
edit: Following example does not quiet work for Either
, see link by huynhjl for more information
However you can besides extracting values from monads in a for-comprehension also create variables, so your example could be rewritten as:
def updateUserStats(user: User): Either[Error,User] = for {
stampleCount <- stampleRepository.getStampleCount(user).right
userUpdated = copyUserWithStats(user,stampleCount)
userSaved <- userService.update(userUpdated).right
} yield userSaved
which saves us an unnecessary allocation and also makes the code more readable.