Ich fing an, Yesod zu verwenden, um ein kleines Projekt zu entwickeln, das ist das erste Mal, dass ich Haskell verwende, um etwas wirklich zu tun. Dieser Code, der ein Anmeldeformular Griffe funktioniert:Haskell: Ausnahmebehandlung in Nicht-IO-Monaden
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()
Nun das Problem ist: Wenn ich zweimal mit den gleichen Zugangsdaten loggen ich eine InternalServerError
bekommen. Das ist richtig, denn in meiner Modellkonfiguration gibt es . Also möchte ich diesen Fehler auf irgendeine Weise erfassen und behandeln. Wie kann ich das im Allgemeinen tun und wie funktioniert die Ausnahmebehandlung in Haskell, wenn Sie mit Nicht-IO-Monaden arbeiten, die in einer externen Bibliothek oder einem externen Framework definiert sind?
PS: Ich lese this Tutorial, aber das ist nützlich, wenn Sie eine neue Bibliothek entwerfen. Ich habe versucht, die Catch-Funktion zu verwenden, aber ich habe viele Typfehler bekommen.
bearbeiten
Danke Ankur arbeitete Ihr Code mit einer kleinen Änderung, um diesen Fehler zu entfernen:
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)
Code:
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))
Mit ScopedTypeVariables
Erweiterung aktiviert
Edit 2
Endfassung nach bennofs' Hinweis:
{-# 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)
Sie [checkUnique] (http://hackage.haskell.org/packages/archive/persistent/0.3.1.3/doc/html/Database-Persist.html#v:checkUnique) verwenden könnte der Schlüssel zu testen, ob ist vor dem Einfügen eindeutig, und vermeiden Sie die Ausnahme, indem Sie diesen Fall anders behandeln. – bennofs
Umh ... es gibt kein checkUnique in den neueren Versionen von Yesod, aber ich fand [insertUnique] (http://hackage.haskell.org/packages/archive/persistent/latest/doc/html/Database-Persist-Class .html # v: insertUnique), danke. Trotzdem bin ich immer noch am Ausnahmehandling interessiert. – andrebask
Sie können 'ScopedTypeVariables' Spracherweiterung verwenden und dann' (\ (e :: SomeException) -> False) ' – Ankur