I'm writing a toy example to learn Haskell database access with the Persistent library. To play around, I want to see what's in the DB (SQLite in Memory):
import qualified Database.Persist.Sql as PSQL
import qualified Data.Conduit.List as CL
import Data.Conduit ( ($$) )
import Control.Monad.IO.Class (liftIO)
dumpTable :: Text -> IO ()
dumpTable tableName = PSQL.rawQuery "select * from " <> tableName [] $$ CL.mapM_ (liftIO . print)
(Taken from the School of Haskell)
Because I want to use the RIO libraries for my applications, the above does not work: I need to use one of the RIO logging functions instead of print, and the function must run in the RIO monad. Here is my attempt to do so:
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
[..]
import RIO
import qualified Database.Persist.Sql as PSQL
import Data.Conduit ( ($$) )
import qualified Data.Conduit.List as CL
dumpTable :: (HasLogFunc env) => Text -> RIO env ()
dumpTable tableName =
let query = "select * from " <> tableName
in PSQL.rawQuery query [] $$ CL.mapM_ (logInfo . displayShow)
However, this code does not type check. I get the following error:
• Could not deduce (PSQL.BackendCompatible PSQL.SqlBackend env)
arising from a use of ‘PSQL.rawQuery’
from the context: HasLogFunc env
bound by the type signature for:
dumpTable :: forall env. HasLogFunc env => Text -> RIO env ()
at src/Persistence/DbInspect.hs:13:1-51
• In the first argument of ‘($$)’, namely ‘PSQL.rawQuery query []’
In the expression:
PSQL.rawQuery query [] $$ CL.mapM_ (logInfo . displayShow)
In the expression:
let query = "select * from " <> tableName
in PSQL.rawQuery query [] $$ CL.mapM_ (logInfo . displayShow)
|
16 | in PSQL.rawQuery query [] $$ CL.mapM_ (logInfo . displayShow)
| ^^^^^^^^^^^^^^^^^^^^^^
I do not understand what this error means. It would be great if someone could give me some hints on how to go ahead and analyse this error, thereby improving my understanding of the involved typeclasses and monads.
Firstly instead of
you probably want this
Now assuming this version, what you have done here is you have selected a concrete type
IO
fordumpTable
which should not type check.The function should be written like this
I don't know which specific example you might be referring to but a simple example for
runQuery
would look something like thisAbove example is from Dumping a table
Without going into too much details, the way to satisfy these constraints
ReaderT SqlBackend (NoLoggingT (ResourceT IO))
is by using each monad transformers'run
functions. ForReaderT
that would berunReaderT
i.e.runReaderT configData $ monadReaderConstraiendFunction
.Anyways, you might want to take a look at how
Monad Transformers
work before diving into this library. It won't take too long, and once you get the gist of it you'll be able to debug any further problems.Speaking of which, now lets take a look at this part of the error message
and your function type
The monad
env
is constrained onHasLogFunc
but the functionrawQuery
requires several other contexts to work in as we saw above.You can see that from
rawQuery
's function type(MonadResource m, MonadReader env m, BackendCompatible SqlBackend env)
.Basically we need to help GHC out by explicitly defining those in its type signature. I don't know how you're interacting with the
RIO
monad, but the most general case should look like thisNow this will type check.