用于理解的 ADT

ADT with for comprehension

我有一个用例,我需要在 Scala 中使用 ADT 进行理解。我可以使用 flatMaps 编写相同的代码,但它似乎有点不可读。下面是一段代码。

case class MovieRecord(movie: Movie,
                       screenId: String,
                       availableSeats: Int,
                       reservedSeats: Option[Int] = None) {
  def movieInfo = new MovieInfoResponse(movie.imdbId, screenId, movie.title, availableSeats, reservedSeats.getOrElse(0))
}


sealed trait MovieBookingInformation
case class MovieBookingInformationFetched(bookMovie: MovieRecord) extends MovieBookingInformation
case object MovieBookingInformationFetchError extends MovieBookingInformation


def modifyBooking(reserveMovie: MovieSelected): Future[String] = {
 fetchRecordByImdbAndScreenId(reserveMovie.imdbId, reserveMovie.screenId) flatMap {
    case MovieBookingInformationFetched(m) if (m.availableSeats > 0) =>
      updateSeatReservationByImdbAndScreenId(m.copy(availableSeats = m.availableSeats - 1, reservedSeats = Some(m.reservedSeats.getOrElse(0) + 1))) flatMap {
        case MovieBookingUpdated(updatedMovieBooking) =>
          Future.successful(s"One seat reserved at Screen - ${updatedMovieBooking.screenId}")
        case MovieBookingUpdateFailed =>
          Future.successful(s"Movie seat reservation failed at screen ${reserveMovie.screenId}")
      }
    case MovieBookingInformationFetched(m) =>
      Future.successful(s"Sorry! No more seats available for ${m.movie.title} at Screen - ${m.screenId}")
    case MovieBookingInformationFetchError => Future.successful(s"No movie with IMDB ID ${reserveMovie.imdbId} found at ${reserveMovie.screenId}")
  }
}

在上面的代码中,对生成的 ADT 内容和 if 语句的结果调用 next 方法。如何在 for-comprehension 中包含 if 语句以实现相同的目的。

提前致谢。

您可以将模式匹配和 if 语句放在 Future:

的 for comprehension 中
for {
  MovieBookingInformationFetched(m) <- future1
  if m.availableSeats > 0
  MovieBookingUpdated(updatedMovieBooking) <- future2(m)
} yield updatedMovieBooking

但是,这会被翻译成Future.filter,所以如果谓词不满足,或者模式无法匹配,你最终会得到

Future.failed(new NoSuchElementException("Future.filter predicate was not satisfied")

然后您可以在 for-comp 之后的 recover 语句中捕获此失败。问题是你想抓住三个不同的 "errors":没有更多可用座位的事实,fetchRecordByImdbAndScreenId 可以 return 和 MovieBookingInformationFetchError 的事实,以及 MovieBookingInformationFetchError 的事实updateSeatReservationByImdbAndScreenId 可以 return 一个 MovieBookingUpdateFailed.

除非您定义自定义异常而不是自定义结果类型(并在之后恢复这些异常),否则您将无法仅使用理解来区分这三者。