Doobie - 将任意效果提升到 ConnectionIO
Doobie - lifting arbitrary effect into ConnectionIO
我正在尝试在使用 Doobie 将用户插入数据库的同一事务中发送电子邮件。
我知道我可以通过使用 Async[ConnectionIO].liftIO(catsIO)
where catsIO: IO[String]
将 IO
提升到 ConnectionIO
但是在我的代码中我不对 IO
进行操作,我使用 F
有约束,例如 F[_]: Async
这样我就可以用我自己的 monad 替换 F
进行测试。
是否可以在不直接使用 IO
类型的情况下以某种方式将 F[String]
提升为 ConnectionIO[String]
?
这是我为 IO 类型找到的答案:
是的,您可以轻松地将 F[String]
实例化为 ConnectionIO[String]
。
给定一个函数,如:
def foo[F[_]: Async]: F[String] = ...
要实例化到 ConnectionIO
你可以简单地这样做:
def fooCIO: ConnectionIO[String] = foo[ConnectionIO]
Cats 有一个叫做 FunctionK 的东西,它是一种自然变换。
我这样做了:
在世界之巅,一切都在这里建造,你将需要这个
val liftToConnIO: FunctionK[IO, ConnectionIO] = LiftIO.liftK[ConnectionIO]
在class中需要从F[String]转为G[String](F会是IO,G会是ConnectionIO当你构造一切)你可以通过liftToConnIO
并使用它在需要的地方将 F[A] 转换为 G[A]。
不想抽象过IO和ConnectionIO的class可以通过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 ()
}
(您可能需要 F 和 G 上的上下文边界(同步?))
Channing 答案的变体,
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]
支持通过 toIO
将 F[A]
转换为 IO[A]
,LiftIO[G]
支持将 IO[A]
转换为 G[A]
通过 to[G]
.
我正在尝试在使用 Doobie 将用户插入数据库的同一事务中发送电子邮件。
我知道我可以通过使用 Async[ConnectionIO].liftIO(catsIO)
where catsIO: IO[String]
将 IO
提升到 ConnectionIO
但是在我的代码中我不对 IO
进行操作,我使用 F
有约束,例如 F[_]: Async
这样我就可以用我自己的 monad 替换 F
进行测试。
是否可以在不直接使用 IO
类型的情况下以某种方式将 F[String]
提升为 ConnectionIO[String]
?
这是我为 IO 类型找到的答案:
是的,您可以轻松地将 F[String]
实例化为 ConnectionIO[String]
。
给定一个函数,如:
def foo[F[_]: Async]: F[String] = ...
要实例化到 ConnectionIO
你可以简单地这样做:
def fooCIO: ConnectionIO[String] = foo[ConnectionIO]
Cats 有一个叫做 FunctionK 的东西,它是一种自然变换。
我这样做了:
在世界之巅,一切都在这里建造,你将需要这个
val liftToConnIO: FunctionK[IO, ConnectionIO] = LiftIO.liftK[ConnectionIO]
在class中需要从F[String]转为G[String](F会是IO,G会是ConnectionIO当你构造一切)你可以通过liftToConnIO
并使用它在需要的地方将 F[A] 转换为 G[A]。
不想抽象过IO和ConnectionIO的class可以通过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 ()
}
(您可能需要 F 和 G 上的上下文边界(同步?))
Channing 答案的变体,
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]
支持通过 toIO
将 F[A]
转换为 IO[A]
,LiftIO[G]
支持将 IO[A]
转换为 G[A]
通过 to[G]
.