Multiple base numbers parser This code is a Parser that parses numbers according to R5RS. 


#b1001 - binary
#o2127 - octal
#h02d  - hexadecimal
#d1231 - decimal
3923 - decimal  


It is working at the moment, the only problem is the parseNumberBase. I am really new to haskell, but it does not look very good to me.


How could I improve it? (readability wise)
It would also be nice to see a more "idiomatic" approach




import Data.Char (digitToInt)
import Numeric (readInt, readOct, readHex)
import Data.Maybe (listToMaybe, fromJust)

parseNumber :: Parser LispVal
parseNumber = parseNumberBase 'd'
          &lt;|&gt; do char '#'
                 base &lt;- oneOf "bdoh"
                 parseNumberBase base

-- | Parses a number at a specific base
parseNumberBase :: Char -&gt; Parser LispVal
parseNumberBase 'b' =
    do digits &lt;- many1 (oneOf "01")
       return $ (Number . fromJust . readBinary) digits
parseNumberBase 'o' =
    do digits &lt;- many1 octDigit
       return $ Number (fst (readOct digits !! 0))
parseNumberBase 'd' =
    do digits &lt;- many1 digit
       return $ (Number . read) digits
parseNumberBase 'h' =
    do digits &lt;- many1 hexDigit
       return $ Number (fst (readHex digits !! 0))
parseNumberBase _ =
    error "Wrong number base"

readBinary :: String -&gt; Maybe Integer
readBinary =
    fmap fst . listToMaybe . readInt 2 (`elem` "01") digitToInt
do
   digits &lt;- someParser
   return $ someFunction digits


is just

someFunction &lt;$&gt; someParser


We can make parseNumberBase a lot shorter with that information:

-- | Parses a number at a specific base
parseNumberBase :: Char -&gt; Parser LispVal
parseNumberBase 'b' = Number . fromJust . readBinary &lt;$&gt; many1 (oneOf "01")
parseNumberBase 'o' = Number . fst . head . readOct  &lt;$&gt; many1 octDigit     -- see below
parseNumberBase 'd' = Number . read                  &lt;$&gt; many1 digit
parseNumberBase 'h' = Number . fst . head . readHex  &lt;$&gt; many1 hexDigit     -- see below
parseNumberBase _   = error "Wrong number base"


readFunc digits !! 0 is head (readFunc digits), so we were able to get rid of !! too.

That being said, parseNumberBase has a lot of responsibility. Split it into multiple parsers, and it's suddenly a lot easier to grasp:

parseBinary :: Parser LispVal
parseBinary = Number . fromJust . readBinary &lt;$&gt; many1 (oneOf "01")

parseDecimal :: Parser LispVal
parseDecimal = Number . read &lt;$&gt; many1 digit

parseHexadecimal :: Parser LispVal
parseHexadecimal = Number . fst . head . readHex &lt;$&gt; many1 hexDigit

parseOct :: Parser LispVal
parseOct = Number . fst . head . readOct  &lt;$&gt; many1 octDigit


We can now test all those functions in isolation. We can now write parseNumberBase as another parser:

parseNumber :: Parser LispVal
parseNumber = parseDecimal &lt;|&gt; char '#' *&gt; parseNumberBase

parseNumberBase :: Parser LispVal
parseNumberBase =  char 'h' *&gt; parseHexadecimal 
               &lt;|&gt; char 'd' *&gt; parseDecimal 
               &lt;|&gt; char 'o' *&gt; parseOct
               &lt;|&gt; char 'b' *&gt; parseBinary