Listen up, oh younger one,
as this is a maddening song.
Take a look and you will see
read :: String -> Int
is wrong for ye.
Its type is wrong, its result is unknown;
if been used on a string like "frown"
.
But here is for the final hint
you're looking for readMaybe :: String -> Maybe Int
.
The problem with read
is that there is no notion of failure in its type signature:
read :: Read a => String -> a
What happens if we set a
to Int
and try to use it on the string "frown"
? It will result in an exception:
ghci> read "frown" :: Int
*** Exception: Prelude.read: no parse
After all, what should it return? Anything from the domain of Int
is a valid value.
Enter readMaybe :: Read a => String -> Maybe a
. Now the potential error is covered in the type signature, and it does not result in an exception anymore:
ghci> import Text.Read
ghci> readMaybe "frown" :: Maybe Int
Nothing
ghci> readMaybe "15" :: Maybe Int
Just 15
We can wrap this in a new function called getNumber
that repeatedly asks for an Int
until the user actually provides one:
getNumber :: IO Int
getNumber = do
line <- getLine
case (readMaybe line :: Maybe Int) of
Just x -> return x
Nothing -> putStrLn "Please enter a number!" >> getNumber
You can then use it to get an Int
instead of a String
for your 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)