In this case, Maybe
may not suffice: You have three conditions to worry about:
- The user entered nothing
- The user input was valid
- The user input was unparsable
This data type and function express this directly:
data Input a = NoInput | Input a | BadInput String
deriving (Eq, Show)
input :: (Read a) => String -> Input a
input "" = NoInput
input s =
case filter (null.snd) (reads s) of
((a,_):_) -> Input a
otherwise -> BadInput s
Note that rather than using the incomplete function read
, it uses reads
which will not error on input which cannot be converted. reads
has a somewhat awkward interface, alas, so I almost always end up wrapping it in a function that returns Maybe a
or something like this here.
Example use:
> input "42" :: Input Int
Input 42
> input "cat" :: Input Int
BadInput "cat"
> input "" :: Input Int
NoInput
I would code your yearFilter
function like this:
yearFilter :: Maybe Int -> Int -> Bool
yearFilter Nothing _ = True
yearFilter (Just x) y = x == objectYear y
Then I'd handle user input as:
inputToMaybe :: Input a -> Maybe a
inputToMaybe (Input a) = Just a
inputToMaybe _ = Nothing
do
a <- input `fmap` getLine
case a of
BadInput s -> putStrLn ("Didn't understand " ++ show s)
otherwise -> ... yearFilter (inputToMaybe a) ....
N.B.: I've cleaned up the code in yearFilter
a bit: no need to use guards to produce a boolean from a test - just return the test, function application (objectYear
) binds tighter than operators (==
) so removed parenthesis, replaced names of unused inputs with _
.
Okay, I admit I can't help myself.... I've rewritten yearFilter
yet again, this time as I would be inclined to write it:
yearFilter :: Maybe Int -> Int -> Bool
yearFilter x y = maybe True (== objectYear y) x
Learning about Maybe
and maybe
was first thing about Haskell that really made me love the language.