1

I'm trying to convert an integer from decimal integer to a string based on base 4, but my unfoldr doesn't work and I'm not sure why or how to replace it. I can't use imports either. Please help me fix this.

dec2Base4 :: Int -> String
dec2Base4 = map i2c . reverse . unfoldr decomp
    where
    decomp n = if n == 0 then Nothing else Just(n `mod` 4, n `div` 4)
    i2c i = if i == 0 then '0' else if i == 1 then '1' else if i == 2 then '2' else '3'

Example: dec2Base4 10-> "22"

Yuki2222
  • 33
  • 4
  • Works for me. What goes wrong for you? – Daniel Wagner Apr 20 '21 at 13:24
  • `$ghc -O2 --make *.hs -o main -threaded -rtsopts [1 of 1] Compiling Main ( main.hs, main.o ) main.hs:46:33: error: • Variable not in scope: unfoldr :: (Integer -> Maybe (Integer, Integer)) -> Int -> [Integer] • Perhaps you meant ‘foldr’ (imported from Prelude)` – Yuki2222 Apr 20 '21 at 13:30
  • are you allowed to use `iterate`? `scanl`? `unfoldr` can be implemented in terms of both (or with direct recursion). `scanl` can be implemented in terms of [`zip` and `map`](https://stackoverflow.com/a/11951590/849891)... – Will Ness Apr 20 '21 at 13:39
  • meta: if you have several accounts you can ask moderators to unite the accounts into one. (I'm not sure about the exact procedure). – Will Ness Apr 20 '21 at 13:42
  • You could start with an auxiliary string obtained thru recursion: `let { auxStr 0 = "" ; auxStr n = let (q,r) = divMod n 4 in (i2c r) : (auxStr q) }` – jpmarinier Apr 20 '21 at 15:11

1 Answers1

1

Your code is basically OK, but it would need you to import the unfoldr function from the Data.List package.

The fact that you are banned from using import clauses might just mean that the powers that be want you to use plain recursion.

A recursion-based solution:

Unfortunately, recursion will naturally produce the least significant digit (rightmost digit) first, because this rightmost digit is essentially mod n 4. You will have to use the reverse function to correct that, just like in your library-based code.

For example, without the help of any non-Prelude library functions, the dec2Base4 function can be written like this:

dec2Base4 :: Int -> String
dec2Base4 n
    |  (n < 0)    =  '-' : (reverse (auxStr (-n)))
    |  (n == 0)   =  "0"
    |  otherwise  =  reverse (auxStr n)  -- when n > 0
  where
    i2c i     =  "0123" !! i
    auxStr 0  =  ""
    auxStr n  =  let  (q,r) = (divMod n 4)  in  (i2c r) : (auxStr q)

Testing code:

unitTest :: Int -> IO ()
unitTest n = do
    let res = dec2Base4 n
    putStrLn $ "Result for " ++ (show n) ++ " is: " ++ res

main = do
    let  testList = [0,11,2051,-2051]
    mapM_  unitTest  testList

Test program output:

Result for 0 is: 0
Result for 11 is: 23
Result for 2051 is: 200003
Result for -2051 is: -200003
jpmarinier
  • 4,427
  • 1
  • 10
  • 23
  • 1
    with tail recursion there's no need to reverse. consider `auxStr n acc = let (q,r) = (divMod n 4) in auxStr q (i2c r : acc)`. :) – Will Ness Apr 20 '21 at 23:37