I was coding a for comprehension, and wondered something:
def updateUserStats(user: User): Either[Error,User] = for {
stampleCount <- stampleRepository.getStampleCount(user).right
userUpdated <- Right(copyUserWithStats(user,stampleCount)).right // ?????????
userSaved <- userService.update(userUpdated).right
} yield userSaved
def copyUserWithStats(user: User, stamples: Long): User = {
val newStats = user.userStats.copy(stamples = stamples)
user.copy(userStats = newStats)
}
It seems using copyUserWithStats which does not return an Either can't be used directly in the for comprehension, because it doesn't have the map/flatMap methods.
So I wonder, in this case, it is the appropriate solution to use Right(copyUserWithStats(user,stampleCount)).right
It seems to work at least...
By the way, I also tried with Option but it didn't work, can someone explain why?
def updateUserStats(user: User): Either[Error,User] = for {
stampleCount <- stampleRepository.getStampleCount(user).right
userUpdated <- Some(copyUserWithStats(user,stampleCount))
userSaved <- userService.update(userUpdated).right
} yield userSaved
Thanks
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With