我开始使用Yesod来开发一个小项目,这是我第一次使用Haskell来做真正的事情。 这段处理注册表单的代码运行良好:
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单子时,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)
ScopedTypeVariables
语言扩展,然后执行(\ (e :: SomeException) -> return False)
。 - Ankur