选择和理解 [英] Either, Options and for comprehensions

查看:82
本文介绍了选择和理解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为理解编写代码,想知道一些事情:

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

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

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.

所以我想知道,在这种情况下,使用Right(copyUserWithStats(user,stampleCount)).right

So I wonder, in this case, it is the appropriate solution to use Right(copyUserWithStats(user,stampleCount)).right

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

It seems to work at least...

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

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

谢谢

推荐答案

在理解中,所有单子必须是同一类.这意味着您不能混用RightProjectionOption,因为输出必须是Either.这是因为对理解的理解是翻译成嵌套的flatMap/map构造.您的示例如下所示:

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

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

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.

编辑:以下示例无法使Either正常工作,请参阅huynhjl的链接以获取更多信息

edit: Following example does not quiet work for Either, see link by huynhjl for more information

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

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.

这篇关于选择和理解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆