Question

I'm going through Write Yourself a Scheme and am struck at the exercise 4 on this page.

How do I go about this? I've got this far, but have no idea whatsoever where the readHex is supposed to go, must I liftM it ? Do you case match the parser ?

parseNumber = liftM (Number . read) $ choice [many1 digit, char '#' >> oneOf "hd" >>= a]
    where a f = case f of
        'h' -> many1 digit

Also, I don't suppose you can apply <|> on Parser LispVal functions, right?

Was it helpful?

Solution

I've got this far, but have no idea whatsoever where the readHex is supposed to go, must I liftM it ?

Yes, since readHex is most likely a pure function and liftM lifts it into the monadic context of Parser.

Since I don't quite understand what your local function a is good for, I'm leaving it for now and simply use the functions parseDecimal and parseHex. In that case, you could write parseNumber like so:

parseNumber :: Parser LispVal
parseNumber = liftM Number $ parseDecimal <|> parseHex
    where parseDecimal :: Parser Integer
          parseDecimal = liftM read $ many1 digit
          parseHex :: Parser Integer
          parseHex     = liftM readHex $ char '#' >> ... -- parse hex value

Of course you can omit the type signatures, I just added them for clarity.

Also, I don't suppose you can apply <|> on Parser LispVal functions, right?

<|> works for every Parser a.

I recommend reading some material on parser combinators, i.e. the Parsec User Guide.

OTHER TIPS

I've changed the layout a bit, but here is the code example we are considering:

parseNumber = 
    liftM (Number . read) $ 
        choice [many1 digit, char '#' >> oneOf "hd" >>= a]
    where
    a f =
        case f of
            'h' -> many1 digit

I think you are trying to do too many things at the same time before knowing how things should go together. You somehow have to move a readHex into the (Number . read) part instead of read, depending on what type of digits were being read.

Here is a parser for hexadecimal numbers that doesn't use liftM or other fancy combinators:

parseHex :: Parser LispVal
parseHex = do
    char '#'
    char 'x'
    digits <- many1 hexDigit   -- hexDigit is defined by Parsec.
    return (Number (fst (readHex digits !! 0)))

The tricky part here is the extraction of the result of readHex.

You can combine parsers with

try parseHex <|> try parseOct <|> ... <|> parseDec

or get fancy with tuning and inlining and the many tools of Parsec. But I'd start with the basics.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top