5
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.