Assistance making a function more readable and elegant.

Nick Kallen phantom@earthlink.net
Mon, 24 Nov 1997 21:09:51 -0800


I wrote the following monolithic function for one of the parsers I'm working
on:

formData :: Parser Char [Char]
formData = <*> (valid <|> space <|> special)
 where
    valid = satisfy (\c -> not (isMember c ['&', '=', '+', '%']) && isAscii
c)
    space = symbol '+' <@ (\_ -> ' ')
    special = symbol '%' &> satisfy isHexDigit <&> satisfy isHexDigit <@
(\(a, b) -> toChar (hexdigtoInt a * 16 + hexdigtoInt b))
    where
        isHexDigit c = isDigit c || (isMember (toLower c) ['a'..'f'])
        hexdigtoInt c
            |    isDigit c = digtoInt c
            |    otherwise = 9 + toInt (toLower c) - toInt 'a' + 1

I think it looks terrible, is huge, inelegant, etc. I was wondering if
anybody could help me try and make it nicer. Any suggestions on anything at
all, from the algorithm to the choice of variable names, would help.

Since there are no comments I'll explain what the function does.
I define formData as zero or more *valid*, *space*, or *special* characters.
    A valid is any ASCII excluding {'&', '=', '+', '%'}.
    A space is a '+', but I want the parser to actually replace this with a
real space (' ').
    A special is a hex code representing an ascii character. It is written
in the form %xx.
        One converts %ab to hex by (a*16 + b); obviously, some conversions
(hexdigtoint) must be made, and the appropriate checks (isHexDigit) must be
made.

Again, I'm not very proud of the above code, any suggestions would be much
appreciated!

-Nick