在带编号选项的菜单中输入非数字时,停止程序崩溃

-5 haskell

当输入是数字时,我的搜索功能正常工作,但当输入不是时,我的搜索功能会崩溃.我可以添加什么来防止这种情况发生?

searchAge = do
  putStrLn "\n Please type the age of the person you're looking for: \n"
  age <- getLine
  input <- readFile $ "databas.txt"
  putStrLn "\n Here are all the people that matches your search: \n"
  let people = parse input
      output = map personToString (filter (\p -> personAge p == read age) people)
    in putStrLn (unlines output)

putStrLn "Let's get back to the search menu again!"     
searchDatabase
Run Code Online (Sandbox Code Playgroud)

Zet*_*eta 16

听,哦,年轻的,
因为这是一首令人发狂的歌.
看一看,你会发现你
read :: String -> Int错了.

它的类型错了,结果不明;
如果在字符串上使用过"frown".
但这是
你正在寻找的最后提示readMaybe :: String -> Maybe Int.


问题read是它的类型签名没有失败的概念:

read :: Read a => String -> a
Run Code Online (Sandbox Code Playgroud)

如果我们设置会发生什么aInt,并尝试使用它的字符串"frown"?这将导致异常:

ghci> read "frown" :: Int
*** Exception: Prelude.read: no parse
Run Code Online (Sandbox Code Playgroud)

毕竟,它应该回归什么?来自域的任何内容Int都是有效值.

输入readMaybe :: Read a => String -> Maybe a.现在,类型签名中包含潜在错误,并且不再导致异常:

ghci> import Text.Read
ghci> readMaybe "frown" :: Maybe Int
Nothing
ghci> readMaybe "15" :: Maybe Int
Just 15
Run Code Online (Sandbox Code Playgroud)

我们可以将这个包装在一个新的函数中,该函数getNumber会反复询问,Int直到用户实际提供一个:

getNumber :: IO Int
getNumber = do
  line <- getLine
  case (readMaybe line :: Maybe Int) of
     Just x  -> return x
     Nothing -> putStrLn "Please enter a number!" >> getNumber
Run Code Online (Sandbox Code Playgroud)

然后你可以使用它来Int代替String你的age:

searchAge = do
    ...
    age   <- getNumber
    input <- readFile "databas.txt"
    putStrLn "\n Here are all the people that matches your search: \n"
    let people = parse input
        output = map personToString (filter (\p -> personAge p == age) people)
    in putStrLn (unlines output)
Run Code Online (Sandbox Code Playgroud)