A: 

To answer the first part of your question, no (f s) will not be memoised, you would have to do that manually:

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

But I'd use pattern matching instead:

liftReadsToParse p f = p >>= \s -> case f s of
                                        []              -> fail "No parse"
                                        (answer, _) : _ -> return answer
Dave Hinton
+2  A: 

This is a nice idea. A more natural approach that would make your ReadS parser fit in better with Parsec would be to leave off the Parser String at the beginning of the type:

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

This "combinator" style is very idiomatic Haskell - once you get used to it, it makes function definitions much easier to read and understand.

You would then use liftReadS like this in the 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 block.

Regarding some of your other questions:

  1. The function f is applied only once now, so there is nothing to "memoize".
  2. It is common and accepted practice to ignore all except the first parse in a ReadS parser in most cases, so you're fine.
Yitz
Very nice, I don't know why I didn't think to pass the `String` in, and also thanks for reminding me about the `maybe` function.
Dave Tapley