Exercise 2 of this pdf reads:
Once we have the digits in the proper order, we need to double every other one. Define a function
doubleEveryOther :: [Integer] -> [Integer]
Remember that doubleEveryOther should double every other number beginning from the right, that is, the second-to-last, fourth-to-last, ... numbers are doubled.
I created an implementation but it is not doing what I expect it to. Here is my code:
doubleEveryOther'' :: [Integer] -> [Integer]
doubleEveryOther'' [] = []
doubleEveryOther'' [x] = [x]
doubleEveryOther'' s@(_:_:_) =
let x:y:xs = reverse s
in reverse (x : 2 * y : doubleEveryOther'' xs)
and a few examples of it running:
*Main> doubleEveryOther'' [1,2,3,4,5,6,7,8,9]
[1,4,3,8,5,12,7,16,9]
*Main> doubleEveryOther'' [1,2,3,4,5,6,7,8]
[1,4,3,8,10,6,14,8]
However, I expected
*Main> doubleEveryOther'' [1,2,3,4,5,6,7,8,9]
[1,4,3,8,5,12,7,16,9]
*Main> doubleEveryOther'' [1,2,3,4,5,6,7,8]
[2,2,6,4,10,6,14,8]
You see, in the case of an even number of entries, it malfunctions partially through the sequence. My guess is that I am not treating the end of list item []
correctly or I am not using an as-pattern correctly.
As suggested in the comment, since working from left is easier, you can use this procedure:
and this will be like having worked from right.
Here's a solution using a recursive function to do the job
Here's a solution not using recursion
which is probably not as good as the previous, because we are wasting time multiplying half of the numbers by 1; but we're not recursing... Well, honestly my level is low enough that I have no clue which solution is better; nor I know why the second solution
heap overflow
s on[1..1000000]
, while the first still has to give me a result after several seconds. I've also tried doingtake 10 $ doubleEveryOther'' [1..1000000]
in the two cases, but that does not work. Probably neither solution is lazy.