`where radix = ...` returns a function that takes a number and parses it
accordingly. The function is chosed by 'try'ing to read a '#' followed
by any of "bodx" and if that fails assume the base is decimal.
The `>>` sequencing operator is used to combine `char` and `oneOf`, they
are executed one after another, discarding the value of the first.
`readInt` takes a base (2), a predicate returning what chars are valid
and a function that describes the Integer value for a char.
`(\x -> elem x "01")` is a lambda that returns true if x is in "01".
`(read . (:[]))` is interesting. The `.` operator composes the functions
`read` and `:[]`, where `:` is the append to list function and `[]` is
the "first argument", i.e. `:[]` appends an element to the empty list.
`let ((a,_):_) = ...` extracts the number from the `[(Number,String)]`
type returned by the `read*` functions.
Because strings starting with '#' are valid Atoms as well, we need to
parse for numbers first.
import Control.Monad
import Text.ParserCombinators.Parsec hiding (spaces)
import System.Environment
+import Numeric
data LispVal = Atom String
| List [LispVal]
_ -> Atom atom
parseNumber :: Parser LispVal
-parseNumber = do ds <- many1 digit
- let a = read ds
+parseNumber = do toNum <- radix
+ ds <- many1 digit
+ let ((a,_):_) = toNum ds
return $ Number a
+ where radix = do r <- try (char '#' >> oneOf "bodx") <|> return 'd'
+ return $ case r of
+ 'd' -> readDec
+ 'x' -> readHex
+ 'o' -> readOct
+ 'b' -> readInt 2 (\x -> elem x "01") (read . (:[]))
parseExpr :: Parser LispVal
parseExpr = parseString
- <|> parseAtom
<|> parseNumber
+ <|> parseAtom
readExpr :: String -> String
readExpr input = case parse parseExpr "lisp" input of