user17221096
user17221096

Reputation:

Converting from any base(1-61) to any(1-61) in Haskell

I need to write a code, that will translate from any base to any( for 1 base it's Turing machine). I should realize 3 functions using only base library: 1)toDecimal base snumber - convert string number to string decimal number 2)fromDecimal toBase snumber - convert from string decimal to string 1-61 base number 3)convertFromTo fromBase toBase snumber snumber I made something, but i don't know how can i work with strings (that's my first question, sorry if i made something wrong) That's the code i made

fromDecimal :: Int ->Int-> String
fromDecimal _ 0 = "" 
fromDecimal toBase snumber = fromDecimal toBase (snumber `div` toBase) ++ ["0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" !! k]  
            where k = snumber `mod` toBase
toDecimal :: Int -> String -> Int
toDecimal base []  = 0
toDecimal base _| base<0 = error "Use positeve base"
toDecimal base snumber = letters (last snumber) + base * toDecimal base (init snumber) 
    where letters :: Char -> Int 
          letters 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
                    | ch == 'g' = 16
                    | ch == 'h' = 17
                    | ch == 'i' = 18
                    | ch == 'j' = 19
                    | ch == 'k' = 20
                    | ch == 'l' = 21
                    | ch == 'm' = 22
                    | ch == 'n' = 23
                    | ch == 'o' = 24
                    | ch == 'p' = 25
                    | ch == 'q' = 26
                    | ch == 'r' = 27
                    | ch == 's' = 28
                    | ch == 't' = 29
                    | ch == 'u' = 30
                    | ch == 'v' = 31
                    | ch == 'w' = 32
                    | ch == 'x' = 33
                    | ch == 'y' = 34
                    | ch == 'z' = 35
                    | ch == 'A' = 36
                    | ch == 'B' = 37
                    | ch == 'C' = 38
                    | ch == 'D' = 39
                    | ch == 'E' = 40
                    | ch == 'F' = 41
                    | ch == 'G' = 42
                    | ch == 'H' = 43
                    | ch == 'I' = 44
                    | ch == 'J' = 45
                    | ch == 'K' = 46
                    | ch == 'L' = 47
                    | ch == 'M' = 48
                    | ch == 'N' = 49
                    | ch == 'O' = 50
                    | ch == 'P' = 51
                    | ch == 'Q' = 52
                    | ch == 'R' = 53
                    | ch == 'S' = 54
                    | ch == 'T' = 55
                    | ch == 'U' = 56
                    | ch == 'V' = 57
                    | ch == 'W' = 58
                    | ch == 'X' = 59
                    | ch == 'Y' = 60
                    | ch == 'Z' = 61
                    | otherwise = error "Wrong number"

Upvotes: 0

Views: 378

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476493

A String is a list of Chars. You use some functions like (++) and last which are not very efficient when working with lists: (++) works in linear time with the size of the first list, and last will take linear time in the length of the list.

Often when processing lists, the base case is the empty list [], and a pattern (x:xs) with x the head of the list and xs the tail of th elist matches with non-empty lists.

We can define a helper function go that will enumerate over the list, and use a parameter (often named an accumulator) that will keep track of the thus far constructed number.

For each element in the list, we first multiply the accumulator with the base and then we add the value for the given character. We keep doing that until we reach the end of the list, in which case we return the accumulator:

toInt :: Int -> String -> Int
toInt base
    | base <= 0 = error "Invalid base"
    | otherwise = go 0
  where go n [] = n
        go n (x:xs) = go (n * base + letter x) xs

letter :: Char -> Int
letter c
    | '0' <= c && c <= '9' = ord c - ord '0'
    | 'A' <= c && c <= 'Z' = ord c - ord 'A' + 10
    | 'a' <= c && c <= 'z' = ord c - ord 'a' + 36
    | otherwise = error "Invalid character"

For the fromDecimal (perhaps rename it to fromInt) you can work with an accumulator as well: in that case you use a list that you each time prepend with a character, and when you reach 0 for the value, you can return that accumulator. I leave that as an exercise.

Upvotes: 0

Related Questions