Haskell: Raising the read function to a parser-parser

As part of the 4th exercise here, I would like to use a function like reads type readHex with the Parser parseq.

For this, I wrote a function:

 liftReadsToParse :: Parser String -> (String -> [(a, String)]) -> Parser a liftReadsToParse pf = p >>= \s -> if null (fs) then fail "No parse" else (return . fst . head ) (fs) 

What can be used, for example, in GHCI, for example:

 *Main Numeric> parse (liftReadsToParse (many1 hexDigit) readHex) "" "a1" Right 161 

Can anyone suggest any improvement to this approach regarding:

Will the term (fs) be remembered or evaluated twice in the case of null (fs) returning False ? Processing several successful parses, i.e. when length (fs) greater than one, I don’t know how this par par is sorted. Processing the rest of the syntax, i.e. (snd . head) (fs) .
+4
source share
2 answers

This is a good idea. A more natural approach is that your ReadS parser ReadS better in Parsec to leave the Parser String at the beginning of the type:

 liftReadS :: ReadS a -> String -> Parser a liftReadS reader = maybe (unexpected "no parse") (return . fst) . listToMaybe . filter (null . snd) . reader 

This "combinator" style is very idiomatic for Haskell - once you get used to it, it makes it easy to define functions to read and understand.

Then you would use liftReadS in this simple case:

 > parse (many1 hexDigit >>= liftReadS readHex) "" "a1" 

(Note that listToMaybe is in the Data.Maybe module.)

In more complex cases, liftReadS is easy to use inside any Parsec do .

Regarding some of your other questions:

  • The reader function is used only once, so nothing needs to be memoize.
  • In most cases, it is common practice to ignore everything except the first analysis in the ReadS parser, so you're fine.
+3
source

To answer the first part of your question, no (fs) will not be noticed, you will have to do it manually:

 liftReadsToParse pf = p >>= \s -> let fs = fs in if null fs then fail "No parse" else (return . fst . head ) fs 

But instead, I use pattern matching:

 liftReadsToParse pf = p >>= \s -> case fs of [] -> fail "No parse" (answer, _) : _ -> return answer 
0
source

All Articles