2016-06-11 9 views
0

ich durch das Tutorial werde bei https://en.wikibooks.org/wiki/Haskell/Monad_transformersVerständnis MonadTransformer Beispiele

schrieb ich von Codes folgende Stück. Das eine ohne und andere mit MonadTransformer Beispiel:

-- Simple Get Password functions. 
getPassphrase1 :: IO (Maybe String) 
getPassphrase1 = do 
    password <- getLine 
    if isValid password 
    then return $ Just password 
    else return Nothing 


askPassphrase1 :: IO() 
askPassphrase1 = do 
    putStrLn "Enter password < 8 , alpha, number and punctuation:" 
    p <- getPassphrase1 
    case p of 
    Nothing -> do   -- Q1. ### How to implement this with `MonadTrans` ? 
     putStrLn "Invalid password. Enter again:" 
     askPassphrase1 
    Just password -> 
     putStrLn $ "Your password is " ++ password 

-- The validation test could be anything we want it to be. 
isValid :: String -> Bool 
isValid s = length s >= 8 
      && any isAlpha s 
      && any isNumber s 
      && any isPunctuation s 

Eine weitere Verwendung MonadT, die ich selbst geschrieben.

getPassphrase2 :: MaybeT IO String 
getPassphrase2 = do 
    password <- lift getLine 
    guard $ isValid password 
    return password 

askPassphrase2 :: MaybeT IO() 
askPassphrase2 = do 
    lift $ putStrLn "Enter password < 8 , alpha, number and punctuation:" 
    p <- getPassphrase2 
    -- Q1. How to print "Invalid password" ? 
    lift $ putStrLn $ "Your password is " ++ p 

-- The validation test could be anything we want it to be. 
isValid :: String -> Bool 
isValid s = length s >= 8 
      && any isAlpha s 
      && any isNumber s 
      && any isPunctuation s 

main :: IO() 
main = do 
    a <- runMaybeT askPassphrase2 
    return() 

Beide funktioniert.

Aber ich kann nicht verstehen, wie wrong password Unterstützung in MonadTrans Beispiel hinzufügen. ?

Auch ist main Methode ok .. oder es kann auf eine bessere Art geschrieben werden?

+1

Keine Notwendigkeit, einen Wert an "a" zu binden, wenn Sie es nicht verwenden werden; 'main = runMaybeT askPassphrase >> return()' – chepner

Antwort

1

guard ist nicht das, was Sie in der MaybeT Ansatz wollen. Um zu überprüfen, für ein ungültiges Kennwort und Lage sein, eigene Verarbeitung in diesem Fall zu schaffen, würden Sie einfach Ihre ursprüngliche Version von getPassphase verwenden und Lift es in die Sport MaybeT IO Monade:

getPassphease2 = do result <- lift $ getPassphrase1 
        case result of 
         Nothing -> lift $ putStrLn "bad password" 
         Just pw -> lift $ putStrLn "your password is: " ++ pw 

Erklärung ...

Die MaybeT IO Monade ist für IO-Aktionen die Möglichkeit zum Fehlschlagen und mit diesem Fehler automatisch von der Monad behandelt. Wenn irgendein Schritt fehlschlägt, geht die Steuerung den ganzen Weg zurück zu den runMaybeT und runMaybeT Rückgaben Nothing. Es ist wie eine Ausnahme zu werfen.

Der Punkt der Verwendung von MaybeT ist, dass Sie nicht explizit überprüfen müssen, ob ein Schritt fehlgeschlagen ist - dass die Überprüfung von der Monade MaybeT nach jedem Schritt durchgeführt wird. Das bedeutet, dass Sie Code schreiben können, wenn Sie davon ausgehen, dass jeder vorangegangene Schritt erfolgreich war - also als ob Sie auf dem "glücklichen Pfad" wären. Dies bedeutet auch, dass Sie nichts anderes tun können, wenn der vorherige Schritt fehlgeschlagen ist.

Eine Möglichkeit, die MaybeT Version von getPassphrase verwendet, ist dies:

main = do result <- runMaybeT askPassphrase2 
      case result of 
      Just _ -> return() 
      Nothing -> putStrLn "Some failure happened... perhaps wrong password?" 

Das Problem ist, dass, wenn runMaybeT kehrt Nothing es könnte bedeuten, dass jeder Schritt in askPassphrase gescheitert, nicht nur die guard.

Eine weitere Möglichkeit, Ihre MaybeT Version von getPassphrase zu verwenden ist askPassphrase laufen sie mit runMaybeT haben:

askPassphrase2 = do result <- lift $ runMaybeT getPassphrase2 
        case result of 
         Nothing -> lift $ putStrLn "bad password" 
         Just pw -> lift $ putStrLn $ "Your password is " ++ pw 

Hier verwenden wir runMaybeT wie ein Try-catch-Block.

+0

Kannst du 'type' vom letzten Beispiel von' askPassphrase' geben? Entschuldigung für den gleichen Namen der Funktionen für beide Versionen. Ich habe sie nicht als '1' und' 2's umbenannt. Kannst du deine Antwort auch dahingehend ändern? –

+0

Fertig - und ich habe einen Tippfehler im letzten Codebeispiel behoben. – ErikR

+0

Auch - vielleicht diese SO Antwort würde helfen: http://StackOverflow.com/a/32582127/866915 – ErikR