Victor Magalhães
Victor Magalhães

Reputation: 318

Is there any function in Haskell that applies a two argument function to two lists, element by element?

I just wanted to multiply two lists element by element, so I'd pass (*) as the first argument to that function:

apply :: Num a => (a -> a -> a) -> [a] -> [a] -> [a]
apply f xs ys = [f (xs !! i) (ys !! i) | i <- [0..(length xs - 1)]]

I may be asking a silly question, but I actually googled a lot for it and just couldn't find. Thank you, guys!

Upvotes: 1

Views: 1805

Answers (1)

chi
chi

Reputation: 116139

> :t zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
> zipWith (*) [1,2,3] [4,5,6]
[4,10,18]

It's the eighth result provided by Hoogle when queried with your type

(a -> a -> a) -> [a] -> [a] -> [a]

Moreover, when you need to implement your own function, use list !! index only as a last resort, since it usually leads to a bad performance, having a cost of O(index). Similarly, length should be used only when necessary, since it needs to scan the whole list.

In the zipWith case, you can avoid both and proceed recursively in a natural way: it is roughly implemented as

zipWith _ []     _      = []
zipWith _ _      []     = []
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys

Note that this will only recurse as much as needed to reach the end of the shortest list. The remaining part of the longer list will be discarded.

Upvotes: 11

Related Questions