readsYou have a String, it stands for a number or it is garbage,
you want to parse out that number or call it a parse error. How to do it
with read? Answer: use reads instead.
The principle of using reads is exemplified by the following
cases:
reads "" :: [(Integer,String)] reads "abc34" :: [(Integer,String)]
The result is []. This stands for parse errors.
reads "34" :: [(Integer,String)] reads " 34" :: [(Integer,String)]
The result is [(34, "")]. This stands for successful parses,
and you get the number. Note that leading spaces are skipped first. (What about
trailing spaces? See the next case.)
reads "34 " :: [(Integer,String)] reads " 34 " :: [(Integer,String)]
The result is [(34, " ")]. Trailing data
is isolated and served, in case you want to check it, or it contains other
things you want to parse out.
reads "34abc" :: [(Integer,String)] reads " 34abc" :: [(Integer,String)]
The result is [(34, "abc")].
There is a 4th case of getting a list with 2 or more tuples. This
does not happen with the default parsers. But you can make it happen when
you write your own Read instance, if you want to support
an ambiguous grammar, and so there can be multiple correct parses and you
give/get them all in a huge list.
The following allows trailing garbage, e.g., 34abc is
accepted:
main = do
cs <- getLine
case reads cs :: [(Integer,String)] of
[(n, _)] -> print n
_ -> putStrLn "invalid input"
The following bans trailing data, e.g., 34abc is rejected,
since the pattern insists on empty trailing data; the user must enter
34:
main = do
cs <- getLine
case reads cs :: [(Integer,String)] of
[(n, "")] -> print n
_ -> putStrLn "invalid input"
Or perhaps you expect a number followed by a boolean, and that should be the end:
main = do
cs <- getLine
case reads cs :: [(Integer,String)] of
[(n, s1)] -> case reads s1 of
-- type anontation unneeded because "not b" helps infer Bool
[(b, "")] -> putStrLn (show n ++ " " ++ show (not b))
[(_, _)] -> putStrLn "invalid, trailing data"
_ -> putStrLn "invalid second item"
_ -> putStrLn "invalid first item"
Another way, but this time you don't care where the parse error is:
main = do
cs <- getLine
case myreads cs :: [(Integer,Bool,String)] of
[(n, b, "")] -> putStrLn (show n ++ " " ++ show (not b))
_ -> putStrLn "invalid input"
myreads cs0 = [ (x, y, cs2) | (x, cs1) <- reads cs0, (y, cs2) <- reads cs1 ]
Lastly, if you expect unique parses, you may as well forget lists and
turn everything into Maybe:
main = do
cs <- getLine
case myparse cs :: Maybe (Integer,Bool) of
Just (n, b) -> putStrLn (show n ++ " " ++ show (not b))
Nothing -> putStrLn "invalid input"
myparse cs0 = case [ (x, y, cs2) | (x, cs1) <- reads cs0, (y, cs2) <- reads cs1 ] of
[(x, y, "")] -> Just (x, y)
_ -> Nothing
reads is ad-hoc polymorphic; which parser it chooses
(Integer parser? Double parser? Maybe
Integer parser?…) depends on which return type you choose, which
in turn depends on context. Some cases can be inferred, and some other cases
cannot be. For starters, there is no hope a standalone reads cs
can have its type inferred; do not be surprised that more complex cases
cannot be either.
(When in doubt, just give it a try. Add type annotations if the type checker fails.)
Examples of types choosing parsers:
reads " 34,abc" :: [(Integer,String)]
[(34,",abc")]
reads " 34e4,abc" :: [(Double,String)]
[(340000.0,",abc")]
reads " 'x',abc" :: [(Char,String)]
[('x',",abc")]
reads "Just 34,abc" :: [(Maybe Integer,String)]
[(Just 34,",abc")]
reads "(34, True),abc" :: [((Integer,Bool),String)]
[((34,True),",abc")]
Example program that can be completely inferred:
main = do
cs <- getLine
case reads cs of
[(n,"")] -> print (n + length cs)
-- due to length, n::Int is forced
_ -> putStrLn "invalid input"
Example program that completely fails:
main = do
cs <- getLine
case reads cs of
[(n,"")] -> print n
-- not enough operations to pin down the type of n
_ -> putStrLn "invalid input"
I have more Haskell Notes and Examples