这是我上一篇文章的后续内容。 MaybeT and Transactions in runDb
我认为这将是一件很简单的事情,但我一直试图解决这个问题超过一天,但仍然没有取得多大进展。所以以为我会放弃并问!
我刚刚添加了一个try
函数(来自Control.Exception.Lifted
)到我以前的代码,我无法获取代码进行类型检查。 catch
和handle
等变体也存在类似问题。
eauth <- LiftIO (
try( runDb $ do
ma <- runMaybeT $ do
valid <- ...
case ma of
Just a -> return a
Nothing -> liftIO $ throwIO MyException
) :: IO (Either MyException Auth)
)
case eauth of
Right auth -> return auth
Left _ -> lift $ left err400 { errBody = "Could not create user"}
我的runDb
看起来像这样(我还尝试了删除liftIO
的变体):
runDb query = do
pool <- asks getPool
liftIO $ runSqlPool query pool
我收到此错误:
No instance for (Control.Monad.Reader.Class.MonadReader Config IO)
arising from a use of ‘runDb’
In the expression: runDb
In the first argument of ‘try’, namely
‘(runDb
$ do { ma <- runMaybeT ...
我在servant处理程序中运行,我的返回类型是AppM Auth
其中
type AppM = ReaderT Config (EitherT ServantErr IO)
我尝试了许多提升组合,但似乎并没有帮助。我想我会抓住这个机会从头开始弄清楚事情,我也碰到了一堵墙。如果有人能够建议你如何得出答案,那对我来说将是超级有益的。
这是我的思考过程:
runSqlConn :: MonadBaseControl IO m => SqlPersistT m a -> Connection -> m a
IO
monad中,这意味着try
应该工作MonadBaseControl
的定义class MonadBase b m => MonadBaseControl b m | m -> b
。此时我很困惑。这个函数依赖逻辑似乎是建议类型m
指示b
将是什么,但在前一个b
中指定为IO
。 MonadBase
,这也没有给我任何线索。 SqlPersistT
并且也没有找到任何线索。 result <- liftIO (try (evaluate (5 `div` 0)) :: IO (Either SomeException Int))
这样非常简单的问题,并且有效。所以此时我更加困惑。没有runDb
在IO
中工作,所以不应该对我的原始代码起作用吗?我认为我可以通过回溯来解决这个问题,但似乎我的Haskell知识水平还不足以解决问题的根源。感谢人们是否可以提供一步一步的指示,以便找到正确的解决方案。
谢谢!