Adding readHex to a Parsec parser
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 suppos开发者_高级运维e you can apply <|>
on Parser LispVal
functions, right?
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.
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.
精彩评论