7

我正在编写一个用于理解的代码,并且想知道一些事情:

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)
}

似乎使用不返回 Either 的 copyUserWithStats 不能直接在 for 理解中使用,因为它没有 map/flatMap 方法。

所以我想知道,在这种情况下,使用它是合适的解决方案Right(copyUserWithStats(user,stampleCount)).right

它似乎至少可以工作......

顺便说一句,我也尝试了 Option 但它没有用,有人可以解释为什么吗?

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

谢谢

4

1 回答 1

11

为了便于理解,所有单子都必须属于同一类型。这意味着您不能混合RightProjectionand Option,因为输出必须是Either. 这是因为 for-comprehension 被转换为嵌套的 flatMap/map 构造。您的示例如下所示:

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
      }
    }
  }

如果我们现在查看 的签名RightProjection.flatMap,即 def flatMap[AA >: A, Y](f: (B) ⇒ Either[AA, Y]): Either[AA, Y],我们会看到,结果必须是Either,但flatMapofOption有签名flatMap[B](f: (A) ⇒ Option[B]): Option[B]。它返回 anOption并且没有理智的方法可以将 an 转换Option为 an Either

编辑:以下示例不起作用Either,请参阅 huynhjl 的链接以获取更多信息

但是,除了从 monad 中提取值之外,您还可以创建变量,因此您的示例可以重写为:

def updateUserStats(user: User): Either[Error,User] = for {
  stampleCount <- stampleRepository.getStampleCount(user).right
  userUpdated = copyUserWithStats(user,stampleCount)
  userSaved <- userService.update(userUpdated).right
} yield userSaved

这为我们节省了不必要的分配,也使代码更具可读性。

于 2013-04-21T10:25:05.280 回答