首页 文章

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

提问于
浏览
4

我试图读取用户输入的信息并将其解析为 Person 类型,该类型使用 Gender 类型 . 为此,我使用此代码:

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 monad . 使用这个,我得到了这个代码:

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 函数时,我收到错误消息

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

我该如何解决这个问题?编写这段代码,我使用了关于Monad变形金刚的wikibook .

编辑:当我尝试'run'它与 runMaybeT 它被执行,但它根本不是故障保护 . 例如,为年龄输入废话仍会产生类似的输出

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

1 回答

  • 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
    

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

相关问题