Type-safe `read` in Haskell

◇◆丶佛笑我妖孽 提交于 2021-01-27 07:42:25

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!