这是我之前发布的后续内容。 MaybeT and Transactions in runDb从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 ...
我的仆人处理程序内运行,我的退货类型为AppM Auth
,其中
type AppM = ReaderT Config (EitherT ServantErr IO)
我已经尝试过许多提升组合,但似乎没有帮助。我想我会借此机会从头开始弄清楚事情,并且我也打了一堵墙。如果有人能够提出你是如何得出答案的,那对我来说将是非常有益的。
这一直是我的思维过程:
- 我看到
runSqlConn :: MonadBaseControl IO m => SqlPersistT m a -> Connection -> m a
- 所以这似乎暗示这将是在
IO
单子,这意味着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知识水平不足以解决问题的根源。欣赏人们是否可以逐步提供指针以达成正确的解决方案。
谢谢!
是'LiftIO'一个错字,应该是'liftIO'?另外'try'不能改变它正在运行的monad('runDB'没有返回'IO',并且你试图让它返回'IO')。实际上,它看起来像'try'可能对'runDB'本身很好。 – Guvante
您应该为'runDb'提供一个类型签名。 @ Guvante的评论和我的回答都应该明确指出'runDB'不会返回'IO'。既然你使用的异常只有一个值,'Maybe' /'MaybeT' monad对于你正在做的事情来说足够强大。看到我答案的最后部分。如果你仍然有问题,你应该包含你在'runMaybeT'块中的代码。 –
@Guvante,你是对的'LiftIO'是一个错字,你的观察也是正确的。因为我的签名,我最终走下了兔子洞。 – Ecognium