Hi I am new in Haskell and I came across an interesting problem but I was not really sure on how I would go about solving it. I am about to show you only two parts of the qu
The missing component is a way to break down an integer into its digits, and build it back up from there. That's easy:
digits:: Int -> [Int]
digits = map (`mod` 10) . takeWhile (/= 0) . iterate (`div` 10)
undigits :: [Int] -> Int
undigits = foldr f 0 where f i r = 10 * r + i
Then it looks like you need to post-process those digits in two different ways, but only if they match a predicate. Let's build a combinator for that:
when :: (a -> Bool) -> (a -> a) -> a -> a
when p f a = if p a then f a else a
The first case appears when you want to double digits in odd position (from left to right). Again trivial, with the minor inconvenience that digits
breaks down a number by increasing power of ten. Let's prefix each number by its position:
prefix :: [Int] -> [(Int, Int)]
prefix is = let n = length is in zip [n, n-1..1] is
doubleOdd
can now be expressed as
doubleodd :: [Int] -> [Int]
doubleodd = map (snd . when (odd . fst) (id *** double)) . prefix
You mentioned in a comment that when the double number overflows, its digits must be added together. This is the second case I was referring to and is again simplicity itself:
double :: Int -> Int
double = when (>= 10) (sum . digits) . (* 2)
Here is your final program:
program = undigits . doubleodd . tail . digits
... assuming the "between 13 and 15 digits" part is verified separately.
I hope this helps and realize it could be cleaned up a lot. List indices start with 0 which is also an even number and the first element of a list. The list comprehension processes 0,2,4 ... the 1st,2nd and 3rd items.
let f n = [mod n 10] ++ f (div n 10)
let r = [if even i then d*2 else d|(i,d)<-zip [0..] (init.reverse.take 14.f$19283828382133)]
sum [b*(10^a)|(a,b) <- zip [12,11..0] r]
2948684868416
If you want it to handle any length number, the easiest way here is length $ show 19283828382133
but I do have a function somewhere that does that. Use the length as a value in 3 places, once at full value in thetake
function in the composition.
First, you need a way to break some large number into digits.
digits :: Integral x => x -> [x]
digits 0 = []
digits x = digits (x `div` 10) ++ [x `mod` 10]
Which gives you...
Prelude> digits 12345
[1,2,3,4,5]
You can then drop the last digit with init
Prelude> (init . digits) 12345
[1,2,3,4]
The a helper function to map
over odd elements in a list.
mapOdd _ [] = []
mapOdd f (x:[]) = [f x]
mapOdd f (x:y:rest) = f x : y : mapOdd f rest
Giving you...
Prelude> mapOdd (+10) [1..10]
[11,2,13,4,15,6,17,8,19,10]
And a function to get back to a large number...
undigits = sum . zipWith (*) [10^n | n <- [0..]] . reverse
Resulting in...
Prelude> undigits [1, 2, 3, 4]
1234
And putting it all together
Prelude> undigits . mapOdd (*2) . init . digits $ 12345
2264
In functional languages particularly, always try to solve a problem by composing solutions to smaller problems :)