Haskell - Check if position is even/odd

Viewed 176

What I need to do is to apply alternately 2 functions in a list. For example:

(*2) (-3) [4,5,6,7,8]

would result in

[8,2,12,4,16], because 4*2, 5-3, 6*2, 7-3, 8*2...

What I was thinking was

funct :: (a -> b) -> (a -> b) -> [a] -> [b]

and then something like

[f x | x <- xs] however I won't have just "f", but will have the other function as well.

So I was thinking about checking the position of x. If it is an even position, then f x. Otherwise g x.

Could someone help me?

Tks.

2 Answers

You do not really need the index, what you need is a list that alternates between (*2) and (-3). We can make use of cycle :: [a] -> [a] and zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]. We can thus use:

zipWith ($) (cycle [(2*), subtract 3]) [4,5,6,7,8]

Here ($) :: (a -> b) -> a -> b is used to perform a function application. So ($) f x is equivalent to f x.

This gives the expected:

Prelude> zipWith ($) (cycle [(2*), subtract 3]) [4,5,6,7,8]
[8,2,12,4,16]

You could always write this out with explicit recursion, to be completely clear about how it works:

alternateFunctions _ _ [] = []
alternateFunctions f g (x:xs) = f x:alternateFunctions g f xs

For an empty list, there's nothing to do. Otherwise, apply the first function to the first element, and recurse for the rest of the list with the first and second functions switched. With that, you have alternateFunctions (*2) (subtract 3) [4,5,6,7,8] = [8,2,12,4,16], as desired.

If you care about performance, then you should rewrite this as a foldr, so that it can fuse:

alternateFunctions f g xs = foldr go mempty xs f g
  where go x acc f g = f x:acc g f
Related