将 Persistent 与 RIO 日志记录相结合以转储 table
Combining Persistent with RIO logging to dump a table
我正在编写一个玩具示例来学习 Haskell 使用 Persistent 库访问数据库。为了玩,我想看看数据库中有什么(内存中的 SQLite):
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)
(取自Haskell的学校)
因为我想为我的应用程序使用 RIO 库,上面的方法不起作用:我需要使用 RIO 日志记录函数之一而不是打印,并且该函数必须 运行 在 RIO monad 中.这是我这样做的尝试:
{-# 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)
但是,这段代码没有进行类型检查。我收到以下错误:
• 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)
| ^^^^^^^^^^^^^^^^^^^^^^
我不明白这个错误是什么意思。如果有人能给我一些关于如何继续分析这个错误的提示,从而提高我对所涉及的类型类和 monad 的理解,那就太好了。
先代替
dumpTable :: Text -> IO ()
dumpTable tableName = PSQL.rawQuery "select * from <> tableName" [] $$ CL.mapM_ (liftIO . print)
你可能想要这个
dumpTable :: Text -> IO ()
dumpTable tableName = PSQL.rawQuery ("select * from " <> tableName) [] $$ CL.mapM_ (liftIO . print)
现在假设这个版本,你在这里所做的是你为 dumpTable
选择了一个具体类型 IO
, 不应该 类型检查。
函数应该这样写
dumpTable
:: (MonadResource m, MonadReader env m,
BackendCompatible SqlBackend env) =>
Text -> m ()
dumpTable tableName = PSQL.rawQuery ("select * from " <> tableName) [] $$ CL.mapM_ (liftIO . print)
我不知道您指的是哪个具体示例,但 runQuery
的简单示例看起来像这样
main :: IO ()
main = runSqlite ":memory:" $ do
buildDb
dumpTable
buildDb
:: ReaderT SqlBackend (NoLoggingT (ResourceT IO)) (Key Tutorial)
buildDb = do
runMigrationSilent migrateTables
insert $ Tutorial "Basic Haskell" "https://fpcomplete.com/school/basic-haskell-1" True
insert $ Tutorial "A monad tutorial" "https://fpcomplete.com/user/anne/monads" False
insert $ Tutorial "Yesod usage" "https://fpcomplete.com/school/basic-yesod" True
insert $ Tutorial "Putting the FUN in functors" "https://fpcomplete.com/user/anne/functors" False
insert $ Tutorial "Basic Haskell" "https://fpcomplete/user/anne/basics" False
dumpTable
:: ReaderT SqlBackend (NoLoggingT (ResourceT IO)) ()
dumpTable = rawQuery "select * from Tutorial" [] $$ CL.mapM_ (liftIO . print)
以上例子来自Dumping a table
无需赘述太多细节,满足这些约束的方法 ReaderT SqlBackend (NoLoggingT (ResourceT IO))
是使用每个 monad 转换器的 run
函数。对于 ReaderT
那将是 runReaderT
即 runReaderT configData $ monadReaderConstraiendFunction
.
无论如何,在深入研究这个库之前,您可能想看看 Monad Transformers
是如何工作的。不会花太长时间,一旦你掌握了它的要点,你就可以调试任何进一步的问题。
说到这里,我们来看看这部分报错信息
• Could not deduce (PSQL.BackendCompatible PSQL.SqlBackend env)
arising from a use of ‘PSQL.rawQuery’
from the context: HasLogFunc env
和你的函数类型
dumpTable :: (HasLogFunc env) => Text -> RIO env ()
monad env
受限于 HasLogFunc
但函数 rawQuery
需要其他几个 contexts 才能工作,正如我们在上面看到的。
从rawQuery
的函数类型可以看出(MonadResource m, MonadReader env m, BackendCompatible SqlBackend env)
。
基本上我们需要通过在其类型签名中明确定义这些来帮助 GHC。我不知道你是如何与 RIO
monad 交互的,但最一般的情况应该是这样的
dumpTable :: (HasLogFunc env
, PSQL.BackendCompatible PSQL.SqlBackend env
, MonadResource (RIO env)
)
=> Text
-> RIO env ()
dumpTable tableName =
let query = "select * from " <> tableName
in PSQL.rawQuery query [] $$ CL.mapM_ (logInfo . displayShow)
现在这将进行类型检查。
我正在编写一个玩具示例来学习 Haskell 使用 Persistent 库访问数据库。为了玩,我想看看数据库中有什么(内存中的 SQLite):
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)
(取自Haskell的学校)
因为我想为我的应用程序使用 RIO 库,上面的方法不起作用:我需要使用 RIO 日志记录函数之一而不是打印,并且该函数必须 运行 在 RIO monad 中.这是我这样做的尝试:
{-# 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)
但是,这段代码没有进行类型检查。我收到以下错误:
• 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)
| ^^^^^^^^^^^^^^^^^^^^^^
我不明白这个错误是什么意思。如果有人能给我一些关于如何继续分析这个错误的提示,从而提高我对所涉及的类型类和 monad 的理解,那就太好了。
先代替
dumpTable :: Text -> IO ()
dumpTable tableName = PSQL.rawQuery "select * from <> tableName" [] $$ CL.mapM_ (liftIO . print)
你可能想要这个
dumpTable :: Text -> IO ()
dumpTable tableName = PSQL.rawQuery ("select * from " <> tableName) [] $$ CL.mapM_ (liftIO . print)
现在假设这个版本,你在这里所做的是你为 dumpTable
选择了一个具体类型 IO
, 不应该 类型检查。
函数应该这样写
dumpTable
:: (MonadResource m, MonadReader env m,
BackendCompatible SqlBackend env) =>
Text -> m ()
dumpTable tableName = PSQL.rawQuery ("select * from " <> tableName) [] $$ CL.mapM_ (liftIO . print)
我不知道您指的是哪个具体示例,但 runQuery
的简单示例看起来像这样
main :: IO ()
main = runSqlite ":memory:" $ do
buildDb
dumpTable
buildDb
:: ReaderT SqlBackend (NoLoggingT (ResourceT IO)) (Key Tutorial)
buildDb = do
runMigrationSilent migrateTables
insert $ Tutorial "Basic Haskell" "https://fpcomplete.com/school/basic-haskell-1" True
insert $ Tutorial "A monad tutorial" "https://fpcomplete.com/user/anne/monads" False
insert $ Tutorial "Yesod usage" "https://fpcomplete.com/school/basic-yesod" True
insert $ Tutorial "Putting the FUN in functors" "https://fpcomplete.com/user/anne/functors" False
insert $ Tutorial "Basic Haskell" "https://fpcomplete/user/anne/basics" False
dumpTable
:: ReaderT SqlBackend (NoLoggingT (ResourceT IO)) ()
dumpTable = rawQuery "select * from Tutorial" [] $$ CL.mapM_ (liftIO . print)
以上例子来自Dumping a table
无需赘述太多细节,满足这些约束的方法 ReaderT SqlBackend (NoLoggingT (ResourceT IO))
是使用每个 monad 转换器的 run
函数。对于 ReaderT
那将是 runReaderT
即 runReaderT configData $ monadReaderConstraiendFunction
.
无论如何,在深入研究这个库之前,您可能想看看 Monad Transformers
是如何工作的。不会花太长时间,一旦你掌握了它的要点,你就可以调试任何进一步的问题。
说到这里,我们来看看这部分报错信息
• Could not deduce (PSQL.BackendCompatible PSQL.SqlBackend env)
arising from a use of ‘PSQL.rawQuery’
from the context: HasLogFunc env
和你的函数类型
dumpTable :: (HasLogFunc env) => Text -> RIO env ()
monad env
受限于 HasLogFunc
但函数 rawQuery
需要其他几个 contexts 才能工作,正如我们在上面看到的。
从rawQuery
的函数类型可以看出(MonadResource m, MonadReader env m, BackendCompatible SqlBackend env)
。
基本上我们需要通过在其类型签名中明确定义这些来帮助 GHC。我不知道你是如何与 RIO
monad 交互的,但最一般的情况应该是这样的
dumpTable :: (HasLogFunc env
, PSQL.BackendCompatible PSQL.SqlBackend env
, MonadResource (RIO env)
)
=> Text
-> RIO env ()
dumpTable tableName =
let query = "select * from " <> tableName
in PSQL.rawQuery query [] $$ CL.mapM_ (logInfo . displayShow)
现在这将进行类型检查。