MaybeT/Maybe 和 IO:信息的故障安全读取
MaybeT/Maybe and IO: Failsafe reading of information
我正在尝试读取用户输入的信息并将其解析为类型 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 获得 compiles/loaded,但是当我尝试执行 readPersonMaybeT
函数时,我收到错误消息
No instance for (Data.Functor.Classes.Show1 IO)
arising from a use of `print'
In a stmt of an interactive GHCi command: print it
我该如何解决这个问题?编写这段代码时,我使用了关于 Monad Transformers 的wikibook。
编辑:当我尝试用 runMaybeT
'run' 它时,它会被执行,但它根本不是故障安全的。例如,输入无意义的年龄仍然会产生类似
的输出
Person {name: 85, age: *** Exception: Prelude.read: no parse.
如果您仅在请求所有输入后才进行验证,我将只使用 IO monad 和 return 一个 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
如果用户输入的年龄无效,他们将不会被要求输入性别。
我正在尝试读取用户输入的信息并将其解析为类型 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 获得 compiles/loaded,但是当我尝试执行 readPersonMaybeT
函数时,我收到错误消息
No instance for (Data.Functor.Classes.Show1 IO) arising from a use of `print' In a stmt of an interactive GHCi command: print it
我该如何解决这个问题?编写这段代码时,我使用了关于 Monad Transformers 的wikibook。
编辑:当我尝试用 runMaybeT
'run' 它时,它会被执行,但它根本不是故障安全的。例如,输入无意义的年龄仍然会产生类似
Person {name: 85, age: *** Exception: Prelude.read: no parse.
如果您仅在请求所有输入后才进行验证,我将只使用 IO monad 和 return 一个 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
如果用户输入的年龄无效,他们将不会被要求输入性别。