Составление нескольких разных типов монад для понимания - PullRequest
0 голосов
/ 19 октября 2018

Предыдущее название: Составление DBIO в целях понимания

Я не понимаю, почему следующий код даже не компилируется.

Что я хочу сделать / Контекст

Для каждой записи в списке записей о продаже билетов на фильмы вставьте ее, если фильм найден в моей базе данных.

Кажется, проблема в том, что я не могу использовать DBIO для понимания.Это почему?Это потому, что я использую разные типы монад для понимания?

val movieTicketSaleNumbers: List[MovieTicketSale] = cinemaApi.allMovieTicketSales

val insertMetricActions: List[DBIO[UUID]] = for {
  movieTicketSaleNumber: MovieTicketSale <- movieTicketSaleNumbers
  isInDatabaseAction: DBIO[Option[Movie]] = moviesDb.findOneExact(movieTicketSaleNumber.movie.id)
  optionalMovie: Option[Movie] <- isInDatabaseAction
  movieInDatabase: Movie <- optionalMovie
  insertMovieNumbersInDatabaseAction: DBIO[UUID] = insertMovieTicketSale(movieTicketSaleNumber, movieInDatabase)
  movieNumberDbId: UUID <- insertMovieNumbersInDatabaseAction
} yield movieNumberDbId

Вывод компилятора:

[error]  found   : slick.dbio.DBIOAction[java.util.UUID,slick.dbio.NoStream,slick.dbio.Effect.All]
[error]  required: Option[?]
[error]         movieNumberDbId: UUID <- insertMovieNumbersInDatabaseAction
[error]                        ^
[error] [PROJECTPATHPLACEHOLDER]: type mismatch;
[error]  found   : Option[Nothing]
[error]  required: slick.dbio.DBIOAction[?,?,?]
[error]         movieInDatabase: Movie <- optionalMovie
[error]                              ^
[error] [PROJECTPATHPLACEHOLDER]: type mismatch;
[error]  found   : slick.dbio.DBIOAction[Nothing,Nothing,slick.dbio.Effect.All with slick.dbio.Effect]
[error]  required: scala.collection.GenTraversableOnce[?]
[error]         optionalMovie: Option[Movie] <- isInDatabaseAction
[error]                                    ^
[error] three errors found
[error] (Compile / compileIncremental) Compilation failed

1 Ответ

0 голосов
/ 19 октября 2018

Да, это потому, что вы используете разные типы монад для понимания.

Подумайте о ненасыщенной версии.Scala для понимания сводится к серии вызовов map и flatMap.Тип flatMap определяется по существу следующим образом:

def flatMap[F[_], A, B](item: F[A])(fn: A => F[B]): F[B]

Обратите внимание, что при изменении внутреннего типа тип обертки всегда имеет один и тот же тип F. Здесь вы смешиваете тип эффекта DBIOс опцией в том же для понимания - это нарушает определение flatMap.

В вашем случае, если вы хотите сохранить все это в понимании for, вы можете попробовать монаду OptionTТрансформатор от Cats: https://typelevel.org/cats/datatypes/optiont.html. OptionT, по сути, предоставляет оболочку, которая позволяет обрабатывать монадическое значение F[Option[_]] как монадическое значение само по себе.Обратите внимание, что у вас также есть список, который является третьим монадическим типом.Таким образом, ваши вычисления могут выглядеть следующим образом:

import cats._
import cats.data._
import cats.implicits._

val movieTicketSaleNumbers: List[MovieTicketSale] = cinemaApi.allMovieTicketSales

def insertTicket(sale: MovieTicketSale): OptionT[DBIO, UUID] = 
  for {
    movie <- OptionT(moviesDb.findOneExact(sale.movie.id))
    movieNumberDbId <- OptionT.liftF(insertMovieTicketSale(sale, movie))
  } yield movieNumberDbId

val insertMetricActions: List[DBIO[Option[UUID]]] = movieTicketSaleNumbers.map(insertTicket(_).value)

Это даст вам список эффектов, обертывающих необязательные UUID, которые были вставлены.

Для этого вам не нужны Cats, хотя,Вы можете делать то, что хотите, в ванильном Scala, хотя это немного сложнее:

val movieTicketSaleNumbers: List[MovieTicketSale] = cinemaApi.allMovieTicketSales

def insertTicket(sale: MovieTicketSale): DBIO[Option[UUID]] = 
  for {
    movie <- moviesDb.findOneExact(sale.movie.id)
    movieNumberDbId <- movie.map(insertMovieTicketSale(sale, _).map(Option(_))).getOrElse(DBIO.successful(None))
  } yield movieNumberDbId


val insertMetricActions: List[DBIO[Option[UUID]]] = movieTicketSaleNumbers.map(insertTicket(_))

Вероятно, есть более элегантный способ выразить это, особенно преобразование Option[DBIO[UUID]] в DBIO[Option[UUID]].

Надеюсь, это поможет!

...