当输入是数字时,我的搜索功能正常工作,但当输入不是时,我的搜索功能会崩溃。我可以在代码中添加什么来防止这种情况发生?
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
答案 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)