Haskell 如何修复MONADER和MonadIO上约束的函数缺少的IO实例?

Haskell 如何修复MONADER和MonadIO上约束的函数缺少的IO实例?,haskell,monad-transformers,haskell-persistent,Haskell,Monad Transformers,Haskell Persistent,我一直在试图通过结合使用it构建一个项目来更好地理解 该项目的一个模块具有使用 简而言之,服务的工作是与API对话,解析响应,并使用insertMany将响应存储到数据库中 实际的存储操作由 在我的服务上使用runReaderT函数会产生 ghci> :t runReaderT service ghci> (MonadReader ApplicationConfig m, MonadIO m) => SqlBackend -> ExceptT Applic

我一直在试图通过结合使用it构建一个项目来更好地理解

该项目的一个模块具有使用

简而言之,
服务
的工作是与API对话,解析响应,并使用
insertMany
将响应存储到数据库中

实际的存储操作由


在我的
服务上使用
runReaderT
函数会产生

ghci> :t runReaderT service
ghci> (MonadReader ApplicationConfig m, MonadIO m) =>
       SqlBackend -> ExceptT ApplicationError m ()
所以要处理这个问题,我相信我需要像这样使用
runExceptT

runService :: ConnectionString -> IO ()
runService connStr = either print return
  =<< runStdLoggingT (runExceptT $ withPostgresqlConn connStr $ runReaderT service)
这里有什么问题?我可能有一个错误,但我不确定该去哪里查找。

一个问题是没有实例,事实上也没有实例。很少有单子有这样的例子:
IO
(微不足道的例子),还有
Identity
Reader
——就像
IO
上的变压器

解决方案是在使用PostgreSqlConn将
服务
传递给
之前,而不是之后,将
除外的构造函数“剥离”。也就是说,传递一个
SqlBackend->m(ApplicationError())
值,而不是
SqlBackend->ExceptT ApplicationError m()
值。您可以通过使用组合函数来实现这一点


我们仍然必须为
m
选择一个具体的类型,以便它满足
服务
所需的
monawarder应用程序配置m、MonadIO m
约束,以及
使用PostgreSqlConn
所需的
monadLifetio m、MonadLogger m
约束。(实际上,我们可以忘记
MonadIO
,因为
monaduliftio
无论如何都暗示了它)

在代码中,调用
runstdlogging
,并期望深入到
IO
。这意味着
m
应该是
loggingtio
。这很好,因为有一个
monaduliftio
实例,当然还有一个
MonadLogger
实例。但是有一个问题:什么满足了
monawarder应用程序配置
约束?配置从哪里来?这就是第二个错误的原因

解决方案是使
m
类似于
ReaderT ApplicationConfig(LoggingT IO)
runService
函数应采用额外的
ApplicationConfig
参数,并在调用
runstdlogging
之前使用配置调用
runReader



更一般的一点是,monad转换器通常有“passthrough”实例,比如“如果基monad是typeclass C的实例,那么转换后的monad也是C的实例”。例如
MonadLogger m=>MonadLogger(ReaderT r m)
of
monadnliftio m=>monadnliftio(ReaderT r m)
。但是这种实例并不总是存在于每个transformer类型类组合中。

尤其是,
runService-appConf-connStr=print-return=
withPostgresqlConn
  :: (MonadUnliftIO m, MonadLogger m) =>
     ConnectionString -> (SqlBackend -> m a) -> m a
ghci> :t runReaderT service
ghci> (MonadReader ApplicationConfig m, MonadIO m) =>
       SqlBackend -> ExceptT ApplicationError m ()
runService :: ConnectionString -> IO ()
runService connStr = either print return
  =<< runStdLoggingT (runExceptT $ withPostgresqlConn connStr $ runReaderT service)
• No instance for (MonadUnliftIO (ExceptT ApplicationError IO))
        arising from a use of ‘withPostgresqlConn’

• No instance for (MonadReader ApplicationConfig IO)
        arising from a use of ‘service’