I'm going through Write Yourself a Scheme and am struck at the exercise 4 on consulta en esta página.

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?

preguntado el 27 de agosto de 11 a las 16:08

## 2 Respuestas

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

Si desde `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` y `parseHex`. In that case, you could write `parseNumber` al igual que:

``````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.

Respondido 27 ago 11, 23:08

It's not quite this straightforward, because of the type of `readHex :: Num a => String -> [(a, String)]`. Ver esta pregunta for how to deal with that. - Hammar

Thanks! Am closer to understanding now! Will accept your answer shortly if nothing else comes - sobresalir

Monadic parsing is very powerful and actually quite easy, once you worked it out. You might also want to have a look at Control.Applicative, which can lead to more consice parsers sometimes, and the current version of Parsec (because it seems that the tutorial is a bit outdated). - bzn

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

``````parseNumber =
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` en el `(Number . read)` parte en lugar de `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.

Respondido 28 ago 11, 00:08

Regarding the last code snippet - don't forget the 1st rule of of Parsec - "try to avoid `try`". - Stephen Tetley

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.