Reputation: 449
I am trying to use Haskell to read in a list and perform an alternating series, so starting with the first element adding every other and subtracting every other from the second element. For instance [1, 2, 3, 4] would be 1-2+3-4=-2. I thought I had figured out how to do this for lists of a specific length (I wrote it to accommodate empty lists and lists up to 4 elements long), but it doesn't do what I thought it would. It just returns the first element from the list. Here is what I have:
altSeries :: Num a => [a] -> a
altSeries [] = 0
altSeries (x:xs) = if length xs == 1 then x
else if length xs == 2 then x
else if length xs == 3 then (x - xs!!1 + xs!!2)
else (x - xs!!1 + xs!!2 - xs!!3)
Also, what if I wanted to be able to use any list size?
Upvotes: 2
Views: 1392
Reputation: 943
What you want is a list that ultimately looks something like this [1,-2,3,-4]
which you could sum.
You can make a list of alternating sign [1,-1]
. this can be made infinite using the cycle function. let alternatingSigns = cycle [1,-1]
To transform a list of [1,2,3,4]
you can zip the infinite alternating list with your list like this zipWith (*) alternatingSigns input
The whole function would look something like this:
altSeries :: Num a => [a] -> a
altSeries input = let alternatingSigns = cycle [1,-1]
in sum $ zipWith (*) alternatingSigns input
Upvotes: 5
Reputation: 477210
I think it is clear that this solution does not scale: even if you would write up function up to lists with length thousand, it would break from the moment that someone enters a list with thousand and one elements.
List processing usually is done recursively: we process the head (or the first k heads) of a list, and perform recursion on the tail of the list. Furthermore we have a number of basecases (can be one) to terminate recursion.
You already provided a single base case: the empty list:
altSeries [] = 0
In case we enter an empty list, it is clear that we should return 0
. Now we might ask what to do in case we obtain a list of length 1: in that case the list has shape [x]
. So in that case we should return x
, since we should add x
, and can not subtract the second number. So we add:
altSeries [x] = x
Now the question is what to do with lists with length two or more. In that case the list has pattern (x1:x2:t)
with x1
the first element, x2
the second element, and t
the remaining elements. Based on your description we should caculate x1-x2
and add altSeries t
:
altSeries (x1:x2:t) = x1 - x2 + altSeries t
This works since altSeries
will then recursively extract x3
and x4
, so then it will recurse to:
altSeries [x1,x2,x3,x4,x5] = x1 - x2 + altSeries [x3,x4,x5]
= x1 - x2 + x3 - x4 + altSeries [x5]
= x1 - x2 + x3 - x4 + x5
So the full implementation is:
altSeries :: Num n => [n] -> n
altSeries [] = 0
altSeries [x] = x
altSeries (x1:x2:t) = x1 - x2 + altSeries t
Upvotes: 4