MaybeT / Maybe和IO:故障安全阅读信息

时间:2016-08-08 13:52:42

标签: haskell io monad-transformers maybe

我正在尝试读取用户输入的信息并将其解析为使用类型Person的{​​{1}}类型。为此,我使用此代码:

Gender

现在我想让这更安全 - 为了达到这个目的,我尝试使用MaybeT monad。使用这个,我得到了这段代码:

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

它由GHCI编译/加载,但当我尝试执行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" 函数时,我收到错误消息

  

没有(Data.Functor.Classes.Show1 IO)的实例     使用'print&#39;   在交互式GHCi命令的stmt中:打印它

我该如何解决这个问题?编写此代码时,我使用wikibook关于Monad Transformers。

编辑:当我尝试'#39;它与readPersonMaybeT一起执行,但它根本不是故障安全的。例如,为年龄输入废话仍然会产生类似

的输出
  

人{姓名:85,年龄:***例外:Prelude.read:无解析。

1 个答案:

答案 0 :(得分:5)

如果您在请求所有输入后才进行验证,我只会使用IO monad并返回一个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

请注意我们如何在return语句中使用Maybe monad。

如果你想在输入无效值时退出请求输入,我会使用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

如果用户输入的年龄无效,则不会要求他们提供性别。