Either, Options and for comprehensions

前端 未结 1 1305
粉色の甜心
粉色の甜心 2021-01-12 20:46

I was coding a for comprehension, and wondered something:

def updateUserStats(user: User): Either[Error,User] = for {
  stampleCount <- stampleRepository.         


        
相关标签:
1条回答
  • 2021-01-12 21:26

    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.

    0 讨论(0)
提交回复
热议问题