6

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)
4

2 に答える 2