2016-08-08 49 views
4

我想讀取用戶輸入的信息並將其解析爲類型Person,該類型使用Gender類型。要做到這一點,我用這個代碼:MaybeT /可能和IO:故障安全讀取信息

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 

現在我想使這更故障保護 - 來實現這一點,我試圖用MaybeT單子。用這個,我得到這個代碼:

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" 

它得到編譯/由GHCI加載,但是當我嘗試執行readPersonMaybeT功能我得到的錯誤消息

沒有實例(數據.Functor.Classes.Show1 IO)從使用'打印」 的在交互式GHCI命令的語句產生 :打印

我怎樣才能解決這個問題呢?編寫這段代碼,我使用了關於Monad變形金剛的wikibook

編輯:當我試圖'運行'它與runMaybeT它得到執行,但它不是安全的。例如,輸入廢話的年齡仍然導致像

人{姓名:85,年齡:***例外:Prelude.read:沒有解析。

+0

你是怎麼「執行」它的?你使用['runMaybeT'](http://hackage.haskell.org/package/transformers-0.5.2.0/docs/src/Control.Monad.Trans.Maybe.html#runMaybeT)? – pdexter

+0

不,我不知道,我必須打電話給runMaybeT ......但我現在試了一下,並沒有解決真正的問題(請參閱編輯)。 – FlashTek

+0

你應該告訴我們'人'的定義 – ErikR

回答

5

如果你正在做你已要求所有輸入後,才確認,我只想使用IO單子,並返回一個可能:

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 

注意我們是如何使用的也許單子在return聲明中。

,如果你想退出要求輸入一旦輸入的值無效,我會用MaybeT - 如果用戶輸入一個無效的年齡,他們不會被要求性別

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 

+1

在第一個'返回(人<$>純名稱<*> readMaybe a <*> readMaybe克)'也是慣用的,我想。在第二種情況下,我們也可以使用應用式,但實際上我更喜歡它,因爲每一行已經很平淡。 – chi

+0

你的評論中的純粹混淆了我。我們是不是已經在迴歸和fmap的使用者的正確環境中? – amalloy

+0

哦,我現在明白了。我錯過了readMaybe電話的進展。 – amalloy