我開始使用Yesod開發一個小項目,這是我第一次使用Haskell來做一些真正的事情。 此代碼來處理登記表工作正常:Haskell:非IO monads中的異常處理
postRegisterR :: Handler()
postRegisterR = do email <- runInputPost $ ireq textField "email"
user <- runInputPost $ ireq textField "user"
pwd <- runInputPost $ ireq textField "pwd"
cpwd <- runInputPost $ ireq textField "cpwd"
if pwd == cpwd && isValidEmail email
then do
tryInsert email user pwd
setSession "user" user
redirectUltDest SessionR
else do
redirect HomeR
tryInsert :: Text -> Text -> Text -> Handler()
tryInsert email user pwd = do pwdbs <- liftIO $ hashedPwd pwd
_ <- runDB $ insert $ User email user pwdbs
return()
現在的問題是:如果我用相同的憑證登入兩次我得到一個InternalServerError
。這是對的,因爲在我的模型配置中有UniqueUser email username
。所以我想以某種方式捕捉並處理這個錯誤。我該怎麼做,一般來說,當你處理外部庫或框架中定義的非IO monads時,如何在Haskell中執行異常處理?
PS:我讀了this教程,但是如果您正在設計一個新庫,那麼這很有用。我嘗試使用catch函數,但是我遇到了很多類型錯誤。
編輯
謝謝ANKUR,你的代碼稍加修改的工作,消除這種誤差:
Ambiguous type variable `e0' in the constraint:
(Exception e0) arising from a use of `catch'
Probable fix: add a type signature that fixes these type variable(s)
代碼:
tryInsert :: Text -> Text -> ByteString -> Handler Bool
tryInsert email user pwd = HandlerT (\d -> catch (unHandlerT (runDB $ insert $ User email user pwd) d
>> return True)
(\(e :: SomeException) -> return False))
隨着ScopedTypeVariables
擴展啓用
編輯2
最終版本,之後bennofs'提示:
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Exception.Lifted (catch)
import Control.Monad (void)
postRegisterR :: Handler()
postRegisterR = do email <- runInputPost $ ireq textField "email"
user <- runInputPost $ ireq textField "user"
pwd <- runInputPost $ ireq textField "pwd"
cpwd <- runInputPost $ ireq textField "cpwd"
if pwd == cpwd && isValidEmail email
then do
pwdbs <- liftIO $ hashedPwd pwd
success <- tryInsert email user pwdbs
case success of
True -> do setSession "user" user
redirectUltDest SessionR
False -> redirect HomeR
else do
redirect HomeR
tryInsert :: Text -> Text -> ByteString -> Handler Bool
tryInsert email user pwd = do void $ runDB $ insert $ User email user pwd
return True
`catch` (\(e :: SomeException) ->
do return False)
您可以使用[checkUnique](http://hackage.haskell.org/packages/archive/persistent/0.3.1.3/doc/html/Database-Persist.html#v:checkUnique)來測試密鑰是否在插入之前是唯一的,並通過不同的方式處理該情況來避免異常。 – bennofs
嗯......在較新版本的Yesod中沒有checkUnique,但是我發現[insertUnique](http://hackage.haskell.org/packages/archive/persistent/latest/doc/html/Database-Persist-Class .html#v:insertUnique),謝謝。無論如何,我仍然對異常處理感興趣。 – andrebask
您可以使用'ScopedTypeVariables'語言擴展,然後執行'(\(e :: SomeException) - > return False)' – Ankur