问题
Learn You a Haskell discusses the following data type:
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
deriving (Eq, Ord, Show, Read, Bounded, Enum)
The book demonstrates how to use read
to parse a String into a Day
type.
$ read "Saturday" :: Day
Saturday
However, I can pass in a non-Day value, resulting in an exception.
$ read "foo" :: Day
*** Exception: Prelude.read: no parse
What's a type-safe way to use read
in the above example?
回答1:
In addition to the old standard function reads
mentioned by @JonPurdy, there's also the more recently added
Text.Read.readMaybe :: Read a => String -> Maybe a
which is simpler to use when the string contains just one value to parse.
回答2:
You can use reads
, which gives you a list of pairs of parsed values and unparsed remainders:
reads :: Read a => ReadS a
type ReadS a = String -> [(a, String)]
Now you can explicitly match on the result and do whatever you like:
case reads x of
-- foo
[] -> Left "no parse"
-- Saturday
[(day, "")] -> Right (day :: Day)
-- Fridayum
[(_, junk)] -> Left $ "day followed by extra junk: " ++ junk
_ -> Left "ambiguous parse"
Though honestly I would estimate that exceptions have lower cost in GHC’s runtime…
For more complex things, you could write a parser using (for example) Parsec:
day :: Parser Day
day = choice
[ Monday <$ string "Monday"
, ...
] <* eof
And whichever parsing library you choose will have a means, such as Parsec’s parse
, of running a parser and dealing with parse errors.
来源:https://stackoverflow.com/questions/23861884/type-safe-read-in-haskell