Либо, Варианты и для понимания

Я кодировал для понимания и кое-что задавался вопросом:

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

Кажется, что использование copyUserWithStats, которое не возвращает, не может быть использовано непосредственно в для понимания, потому что у него нет методов 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

Спасибо


person Sebastien Lorber    schedule 21.04.2013    source источник


Ответы (1)


В for-понимании все монады должны быть одного вида. Это означает, что вы не можете смешивать RightProjection и 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, то есть по определению flatMap[AA >: A, Y](f: (B) ⇒ Either[AA, Y]): Either[AA, Y], мы увидим, что результатом должно быть Either, но flatMap из Option имеет сигнатуру flatMap[B](f: (A) ⇒ Option[B]): Option[B]. Он возвращает Option, и нет разумного способа перевести Option в Either.

изменить: следующий пример не отключает работу для Either, см. ссылку от huynhjl для получения дополнительной информации.

Однако вы можете помимо извлечения значений из монад в for-comprehension также создавать переменные, поэтому ваш пример можно переписать как:

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

что избавляет нас от ненужного выделения памяти, а также делает код более читаемым.

person drexin    schedule 21.04.2013
comment
Вы пробовали создавать такие переменные? У меня не работает с Either. - person huynhjl; 21.04.2013
comment
stackoverflow.com/ вопросы/10688447/ - person huynhjl; 21.04.2013
comment
Спасибо huynhjl. Честно говоря, я просто ожидал, что это сработает, и не пробовал. - person drexin; 21.04.2013