Doob ie - поднятие произвольного эффекта в ConnectionIO - PullRequest
1 голос
/ 09 января 2020

Я пытаюсь отправить электронное письмо в той же транзакции, что и вставка пользователя в базу данных с помощью Doob ie.
Я знаю, что могу поднять IO в ConnectionIO, используя Async[ConnectionIO].liftIO(catsIO) где catsIO: IO[String]
Но в моем коде я не оперирую IO, я использую F с ограничениями, например F[_]: Async Так что тогда я могу заменить F своей собственной монадой для тестирования.

Можно ли каким-то образом поднять F[String] в ConnectionIO[String] без непосредственного использования типа IO?

Вот ответ, который я нашел для типа ввода-вывода: Doob ie и состав доступа к БД в пределах 1 транзакции

Ответы [ 3 ]

4 голосов
/ 24 апреля 2020

Кошки имеют функцию FunctionK, которая является естественным преобразованием.

Я сделал это:

На вершине мира, где все построено, вам понадобится это

val liftToConnIO: FunctionK[IO, ConnectionIO] = LiftIO.liftK[ConnectionIO]

В классе, нуждающемся в преобразовании из F [String] в G [String] (F будет IO, G будет ConnectionIO, когда вы создаете все), вы можете передать liftToConnIO и использовать его для преобразования F [A ] до G [A], где это необходимо.

Классу, который не хочет абстрагироваться через IO и ConnectionIO, можно передать FunctionK для выполнения подъема:

class Stuff[F[_], G[_]](emailer: Emailer[F], store: Store[G], liftToG: FunctionK[F, G]) {

  def sendEmail: G[Unit] =
    for {
      _ <- doDatabaseThingsReturnStuffInG
      _ <- liftToG(emailer.sendEmail)
      _ <- doMoreDatabaseThingsReturnStuffInG
     } yield ()

}

(Вы можете нужны границы контекста (Syn c?) для F и G)

2 голосов
/ 13 января 2020

Да, вы можете легко создать свой экземпляр F[String] в ConnectionIO[String]. Имея такую ​​функцию, как:

def foo[F[_]: Async]: F[String] = ...

Чтобы создать экземпляр для ConnectionIO, вы можете просто сделать это:

def fooCIO: ConnectionIO[String] = foo[ConnectionIO]
0 голосов
/ 26 апреля 2020

Вариант ответа Ченнинга:

class Stuff[F[_] : Effect, G[_] : LiftIO](emailer: Emailer[F], store: Store[G]) {

  def sendEmail: G[Unit] =
    for {
      _ <- doDatabaseThingsReturnStuffInG
      _ <- emailer.sendEmail.toIO.to[G]
      _ <- doMoreDatabaseThingsReturnStuffInG
     } yield ()
}

Effect[F] поддерживает передачу F[A] в IO[A] через toIO, а LiftIO[G] поддерживает передачу IO[A] в G[A] через to[G].

...