Polysemy: IO
Polysemy provides many ways to combine both effects and interpreters, let's start with a simple Db
effects:
data Db (m :: Type -> Type) a where
ExecQuery :: Statement args a -> args -> Db m a
Some libraries provide dedicated Monad which are expensive to run, for example:
Would force us to embed it:
runDb =
interpret $
\case
ExecQuery s args -> embed $ runQuery s args
We have many interpretations options:
If MonadDb
is a MonadIO
instance, we can use it as such:
runMonadDb $ runM $ embedToMonadIO @MonadDb $ runDb act
Everything will be run as MonadDb
.
Under the hood, it uses runEmbedded
:
runEmbedded
:: forall m1 m2 r a.
Member (Embed m2) r
=> (forall x. m1 x -> m2 x)
-> InterpreterFor (Embed m1) r
Which is more straightforward to use:
runM $ runEmbedded runMonadDb $ runDb act
A last option is to use lowerEmbedded
.
lowerEmbedded
:: (MonadIO m, Member (Embed IO) r)
=> (forall x. m x -> IO x)
-> InterpreterFor (Embed m) r
It creates a run thread to deal with the lowering.
runM $ lowerEmbedded runMonadDb $ runDb act
See the full the code here.