Реализация репозитория с State Monad (используйте IO и State вместе) - PullRequest
0 голосов
/ 18 марта 2019

У меня есть этот репозиторий:

trait TrainRepository {
  def get(trainId: TrainId): IO[Option[Train]]
  def getAll: IO[List[Train]]
  def save(train: Train): IO[Train]
}

Я хотел бы предоставить реализацию в памяти, используя State Monad. Но я застрял:

  • Если я расширю черту, я застряну с типами IO[...], поэтому я считаю, что не смогу использовать Государственную Монаду.
  • мне нужно использовать естественное преобразование?
  • мне нужно использовать Free Monad? (Я бы не хотел)

Как бы вы это сделали?

РЕДАКТИРОВАТЬ, чтобы дать немного больше контекста:

trait TrainRepository[F[_]] {
  def get(trainId: TrainId): F[Option[Train]]
  def save(train: Train): F[Train]
}

class TrainService[F[_]](repository: TrainRepository[F])(implicit monad: Monad[F]) {
  def reservation(id: TrainId): F[Train] =
    for{
      train <- repository.get(id)
      updatedTrain <- train match {
        case None => monad.pure("test") // return error here
        case Some(train) => monad.pure(train.bookSeat) 
      }
      _ <- repository.save(updatedTrain)
    } yield updatedTrain
}


type TrainStateRepository[A] = State[Map[TrainId, Train], A]

val inMemoryTrainRepository = new TrainRepository[TrainStateRepository] {
  override def get(trainId: TrainId): TrainStateRepository[Option[Train]] = ???

  override def save(train: Train): TrainStateRepository[Train] = ???
}


val postgresTrainRepository = new TrainRepository[IO] {
  override def get(trainId: TrainId): IO[Option[Train]] = ???

  override def save(train: Train): IO[Train] = ???
}


val testTrainService = new TrainService[IO](inMemoryTrainRepository)
// The error is here ^^^^
// I cannot mix IO and State

val prodTrainService = new TrainService[IO](postgresTrainRepository)

1 Ответ

1 голос
/ 19 марта 2019

Вы можете ввести параметр типа, чтобы абстрагироваться от вашей монады:

trait TrainRepository[F[_]] {
  def get(trainId: TrainId): F[Option[Train]]
  def getAll: F[List[Train]]
  def save(train: Train): F[Train]
}

Тогда ваша реализация с монадой состояния может выглядеть как

type TrainsState[A] = State[Map[TrainId, Train], A]

class StateTrainRepository extends TrainRepository[TrainsState] {
  override def get(trainId: TrainId): TrainsState[Option[Train]] = State.inspect(_.get(trainId))

  override def getAll: TrainsState[List[Train]] = State.inspect(_.values.toList)

  override def save(train: Train): TrainsState[Train] =
    State.modify[Map[TrainId, Train]](m => m + (train.id -> train)) *> State.pure(train)
}
...