我开始使用 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 monad 时,我该怎么做?一般来说,Haskell 中的异常处理是如何工作的?
PS:我读过这个教程,但是如果你正在设计一个新的库,这很有用。我尝试使用 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)