Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: recursively convert hex string to integer?

For my homework assignment, I need to convert a hexadecimal string to a base-10 integer using a recursive function (with as many helper methods as necessary).

This is what I've got so far:

-- Question 1, part (c):
hexChar :: Char -> Integer
hexChar ch
    | ch == '0' = 0
    | ch == '1' = 1
    | ch == '2' = 2
    | ch == '3' = 3
    | ch == '4' = 4
    | ch == '5' = 5
    | ch == '6' = 6
    | ch == '7' = 7
    | ch == '8' = 8
    | ch == '9' = 9
    | ch == 'A' = 10
    | ch == 'B' = 11
    | ch == 'C' = 12
    | ch == 'D' = 13
    | ch == 'E' = 14
    | ch == 'F' = 15
    | otherwise     = 0

parseHex :: String -> Integer
parseHex hxStr 
    | length hxStr /= 0 = (hexChar(last(hxStr)))+(10*parseHex(init(hxStr)))
    | otherwise         = 0  

However, this does not produce the correct results. Does anyone know of the correct way to do this?

like image 410
Govind Parmar Avatar asked Feb 18 '13 04:02

Govind Parmar


People also ask

How do you convert a char to INT in Haskell?

Now if you're a Haskell hacker, you'll probably laugh about that, but as a newbie I initially had to search for quite a bit in order to find the appropriate functions. So my colleague Matthias found a function called digitToInt which basically converts a Char into an Int type.

What is the difference between not (null) and hxstr in Haskell?

Haskell strings are implemented as linked lists, so length hxStrtakes time proportional to the length of hxStr. In contrast not (null hxStr)takes constant time to compute.

How do you parse a hex string in Python?

parseHex :: String -> Integer parseHex [] = 0 parseHex hxStr = hexChar (last hxStr) + 16 * parseHex (init hxStr)) It's unfortunate that you can't pattern match on hStrright away because you need initand lastinstead of headand tail.

Do I have to tell Haskell what type MY PROGRAM is?

If you are unfamiliar with Haskell's typeclasses, just know that you might have to tell Haskell what type you want to read it as: You don't always have to do this, if Haskell has some other way of knowing what type you want, like if you proceed to do arithmetic with it.


2 Answers

You are really close. your error is on this line:

    | length hxStr /= 0 = (hexChar(last(hxStr)))+(10*parseHex(init(hxStr)))

Think about why you are multiplying by 10. Remember ... Hexadecimal is base 16.

like image 86
Stephen Avatar answered Sep 28 '22 04:09

Stephen


Now that you got the right answer, you should consider the style. Using pattern matching, this looks clearer already:

parseHex :: String -> Integer
parseHex [] = 0
parseHex hxStr = (hexChar(last(hxStr)))+(16*parseHex(init(hxStr)))

And it's also more efficient, as you don't need to evalute length hxStr (which is O(N)) at each recursive call to decide which case applies. Total runtime goes from O(N**2) to O(N).

It looks even better when you drop some parentheses, as groovy suggested:

parseHex :: String -> Integer
parseHex [] = 0
parseHex hxStr = hexChar (last hxStr) + 16 * parseHex (init hxStr))

It's unfortunate that you can't pattern match on hStr right away because you need init and last instead of head and tail. But you can mitigate that using reverse and a helper:

parseHex :: String -> Integer
parseHex hxStr = go (reverse hxStr)
    where go []     = 0
          go (x:xs) = hexChar x + 16 * parseHex xs

That last one may be just a matter of taste though. hexChar also becomes shorter:

hexChar '0' = 0
hexChar '1' = 1
...                  -- other cases here
hexChar _ = 0        -- 'otherwise' case; maybe throw an error instead?
like image 34
firefrorefiddle Avatar answered Sep 28 '22 03:09

firefrorefiddle