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 ()
問題は次のとおりです。同じ資格情報で 2 回サインインすると、InternalServerError
. 私のモデル構成には があるので、これは正しいですUniqueUser email username
。したがって、このエラーを何らかの方法でキャッチして処理したいと思います。外部のライブラリやフレームワークで定義された非 IO モナドを扱っている場合、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)