Haskell 如何修复MONADER和MonadIO上约束的函数缺少的IO实例?
我一直在试图通过结合使用it构建一个项目来更好地理解 该项目的一个模块具有使用 简而言之,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
服务
的工作是与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)
ofmonadnliftio 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’