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

时间:2016-02-23 15:08:23

标签: 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

1 个答案:

答案 0 :(得分:16)

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

它的类型错了,结果未知;
如果用在"frown"之类的字符串上。
但这是最后的暗示 你正在寻找readMaybe :: String -> Maybe Int

read的问题在于其类型签名中没有失败的概念:

read :: Read a => String -> a

如果我们将a设置为Int并尝试在字符串"frown"上使用它会怎样?这将导致异常:

ghci> read "frown" :: Int
*** Exception: Prelude.read: no parse

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

输入readMaybe :: Read a => String -> Maybe a。现在,类型签名中涵盖了潜在的错误,并且它不再导致异常:

ghci> import Text.Read
ghci> readMaybe "frown" :: Maybe Int
Nothing
ghci> readMaybe "15" :: Maybe Int
Just 15

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

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

然后,您可以使用它为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)