Recently I set about to writing conversion functions in Haskell between decimal and negabinary. I tried to write them in as much functional a style as possible, also aiming at brevity. Below I present my take at the task. I'd be interested in your refinements of the method I employ or any comments whatsoever.
These are my two functions for converting back and forth:
type NegaBinary = String
dec2negbin :: Int -> NegaBinary
dec2negbin = reverse .
map intToDigit .
unfoldr (\x -> if x==0 then Nothing else Just(abs(xrem x (-2)), xdiv x (-2)))
where
xrem a b = if b > 0 then rem a b else (-(rem a (-b)))
xdiv a b = if b > 0 then div a b else (-(div a (-b)))
negbin2dec :: NegaBinary -> Int
negbin2dec = sum . map (\x -> (snd x)*(-2)^(fst x)) . zip [0..] . reverse . map digitToInt
I defined the NegaBinary
type just for clarity. The dec2negbin
employs the unfoldr
function for sequential divisions and remainder calculations. I also used two local functions: xrem
and xdiv
, because the standard functions (rem
and div
) had the undesirable behavior of always approaching the dividend from below (meaning that in div a b => c
b*c
is always lower than a
). What I wanted is for it to approach in the direction from zero, so the behavior is different for positive and negative dividends. I know the definition of dec2negbin
is a bit bulky, so improvements are welcome.
1 Answer 1
A couple of things I noticed:
xrem and xdiv are exactly the same except they use a different division function. You could therefore replace them with a single function that takes the type of division as a parameter:
dec2negbin :: Int -> NegaBinary
dec2negbin = reverse .
map intToDigit .
unfoldr (\x -> if x==0 then Nothing else Just(abs(doDiv rem x (-2)), doDiv div x (-2)))
where
doDiv division a b = if b > 0 then division a b else (-(division a (-b)))
In your second function you could use zipWith which applies a given function whilst zipping instead of doing a zip then a map:
negbin2dec :: NegaBinary -> Int
negbin2dec = sum . zipWith raise [0..] . reverse . map digitToInt
where
raise e x = x * (-2) ^ e
Explore related questions
See similar questions with these tags.