gpt4 book ai didi

haskell - 如何为受 MonadReader 和 MonadIO 约束的函数修复丢失的 IO 实例?

转载 作者:行者123 更新时间:2023-12-04 09:40:21 26 4
gpt4 key购买 nike

我一直在努力理解 mtl通过将其与 persistent 结合使用来构建项目.

该项目的一个模块具有使用 insertMany_ 的功能。

service
:: (MonadReader ApplicationConfig m, MonadIO m) =>
ReaderT SqlBackend (ExceptT ApplicationError m) ()
service = insertMany_ =<< lift talkToAPI

这里 talkToAPI可能会失败,因此响应包含在 ExceptT 中, 它的类型是
ExceptT ApplicationError m [Example]

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

实际存储 Action 由 withPostgresqlConn 处理
withPostgresqlConn
:: (MonadUnliftIO m, MonadLogger m) =>
ConnectionString -> (SqlBackend -> m a) -> m a

使用 runReaderT在我的 service函数产量
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)

但我得到这两个错误
• 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’

这里可能是什么问题?我可能有一个错误,但我不确定在哪里寻找。

最佳答案

一个问题是 ExceptT ApplicationError IO 没有——事实上也不能——有 MonadUnliftIO 实例。很少有单子(monad)有这个实例:IO (微不足道的情况)以及IdentityReader类似变压器超过IO .

解决方案是“剥”ExceptT传递前的构造函数 servicewithPostgresqlConn ,而不是之后。也就是说,通过 SqlBackend -> m (Either ApplicationError ())值而不是 SqlBackend -> ExceptT ApplicationError m ()值(value)。您可以通过使用 runExceptT 组合函数来得到它。 .

我们仍然需要为 m 选择具体类型使其满足MonadReader ApplicationConfig m, MonadIO m service 所需的约束还有MonadUnliftIO m, MonadLogger m withPostgresqlConn 所需的约束. (实际上,我们可以忘记MonadIO,因为MonadUnliftIO 无论如何都暗示了它)。

在您的代码中,您调用 runStdLoggingT并期望降到IO .这意味着 m预计为LoggingT IO .没关系,因为 LoggingT 有一个 MonadUnliftIO实例,当然还有 MonadLogger一。但是有一个问题:什么满足 MonadReader ApplicationConfig约束?哪里来的配置?这就是第二个错误的原因。

解决方案是制作 m类似于 ReaderT ApplicationConfig (LoggingT IO) . runService函数需要额外的 ApplicationConfig参数,并调用 runReader在调用 runStdLoggingT 之前使用配置.

更一般的一点是,monad 转换器通常具有“直通”实例,例如“如果基本 monad 是类型类 C 的实例,则转换后的 monad 也是 C 的实例”。例如 MonadLogger m => MonadLogger (ReaderT r m)MonadUnliftIO m => MonadUnliftIO (ReaderT r m) .但是这种实例并不总是存在于每个转换器类型类组合中。

关于haskell - 如何为受 MonadReader 和 MonadIO 约束的函数修复丢失的 IO 实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62360268/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com