2016-08-08 1 views
4

J'essaie de lire l'information entrée par l'utilisateur et de l'analyser dans le type Person, qui utilise le type Gender. Pour ce faire, j'utiliser ce code:Peut-être/IO: Failsafe lecture de l'information

data Person = Person String Int Gender String 
data Gender = Male | Female | NotSpecified deriving Read 

instance Show Gender where 
    show Male = "male" 
    show Female = "female" 
    show NotSpecified = "not specified" 

instance Show Person where 
    show (Person n a g j) = "Person {name: " ++ n ++ ", age: " ++ show a ++ 
     ", gender: " ++ show g ++ ", job: " ++ j ++ "}" 

readPersonMaybeT :: MaybeT IO() 
readPersonMaybeT = do 
    putStrLn "Name?:" 
    name <- getLine 
    putStrLn "Age?:" 
    ageStr <- getLine 
    putStrLn "Gender?:" 
    genderStr <- getLine 
    putStrLn "Job?:" 
    job <- getLine 

    let newPerson = Person name (read ageStr) (read genderStr) job 
    putStrLn $ show newPerson 

Maintenant, je voudrais rendre plus failsafe - pour y parvenir, j'ai essayé d'utiliser la monade MaybeT. Avec cela, je suis arrivé ce code:

readPersonMaybeT :: MaybeT IO() 
readPersonMaybeT = do 
    lift $ putStrLn "Name?:" 
    name <- lift getLine 
    lift $ putStrLn "Age?:" 
    ageStr <- lift getLine 
    lift $ putStrLn "Gender?:" 
    genderStr <- lift getLine 
    lift $ putStrLn "Job?:" 
    job <- lift getLine 

    let newPerson = Person name (read ageStr) (read genderStr) job 
    lift $ putStrLn "show newPerson" 

Il se compiles/chargé par le GHCi, mais lorsque je tente d'exécuter la fonction readPersonMaybeT je reçois le message d'erreur

Aucune instance pour (Data .Functor.Classes.Show1 IO) résultant d'une utilisation de `print » Dans un stmt d'une commande GHCi interactive: imprimer

Comment puis-je résoudre ce problème? En écrivant ce code, j'ai utilisé le wikibook sur les transformateurs Monad.

EDIT: Lorsque j'essaie de 'l'exécuter' avec runMaybeT, il est exécuté, mais il n'est pas du tout sûr. Entrer un non-sens pour l'âge par exemple se traduit toujours par une sortie comme

Personne {nom: 85, âge: *** Exception: Prelude.read: no parse.

+0

Comment l'avez-vous 'exécuté'? Avez-vous utilisé ['runMaybeT'] (http://hackage.haskell.org/package/transformers-0.5.2.0/docs/src/Control.Monad.Trans.Maybe.html#runMaybeT)? – pdexter

+0

Non, je ne savais pas, que je dois appeler runMaybeT ... Mais je l'ai essayé maintenant, et cela n'a pas résolu le vrai problème (voir l'EDIT). – FlashTek

+0

vous devriez nous montrer la définition de 'Person' – ErikR

Répondre

5

Si vous faites la validation seulement après avoir demandé à tous l'entrée, je voudrais simplement utiliser la monade IO et retourner un Maybe:

import Text.Read 
import Control.Monad.Trans.Maybe 
import Control.Monad.IO.Class 

askPerson :: IO (Maybe Person) 
askPerson = do 
    name <- putStr "Name? " >> getLine 
    a <- putStr "Age? " >> getLine 
    g <- putStr "Gender? " >> getLine 
    return $ do age <- readMaybe a 
       gender <- readMaybe g 
       return $ Person name age gender 

Notez la façon dont nous utilisons Maybe monade dans l'instruction return.

J'utiliser MaybeT si vous voulez arrêter de vous demander d'entrer une fois qu'ils entrent dans une valeur non valide -

askPersonT :: MaybeT IO Person 
askPersonT = do 
    name <- liftIO $ putStr "Name? " >> getLine 
    age <- MaybeT $ fmap readMaybe $ putStr "Age? " >> getLine 
    gender <- MaybeT $ fmap readMaybe $ putStr "Gender? " >> getLine 
    return $ Person name age gender 

doit = runMaybeT askPersonT 

Si l'utilisateur entre un âge invalide ils ne seront pas invités pour un sexe.

+1

Dans le premier, 'return (Personne <$> pur nom <*> readMaybe un <*> readMaybe g)' est également idiomatique, je pense. Dans la seconde, nous pouvons aussi utiliser un style applicatif, mais je le préfère en fait comme vous l'avez écrit puisque chaque ligne est déjà non triviale. – chi

+0

Le pur dans votre commentaire me confond. Ne sommes-nous pas déjà dans le bon contexte de l'usr de retour et de fmap? – amalloy

+0

Oh, je comprends maintenant. J'ai raté ce qui se passait avec les appels readMaybe. – amalloy