這是我之前發佈的後續內容。 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