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"

5
  • Works for me. What goes wrong for you? Commented Apr 20, 2021 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) Commented Apr 20, 2021 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... Commented Apr 20, 2021 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). Commented Apr 20, 2021 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) } Commented Apr 20, 2021 at 15:11

1 Answer 1

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
Sign up to request clarification or add additional context in comments.

1 Comment

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). :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.