I've a simple question:
combine :: (a -> b -> c) -> [a] -> [b] -> [c]
combine f (a:as) (b:bs) = f a b : combine f as bs
combine _ _ _ = [ ]
This is recursive. Now i want to use a list comprehension to solve the same problem:
combine f (x:xs) (y:ys) = [ f x y | x <- (x:xs), y <- (y:ys) ]
But my problem is the combination of elements. I only want to combine x1 y1, x2 y2, xs ys ... not x1 y1, x1 y2, x1 ys, x2 y1, x2 y2, ......
Thank you!
What you need is a parallel list compehension. To be able to use it you need to specify a ParallelListComp pragma to the compiler:
{-# LANGUAGE ParallelListComp #-}
combine :: (a -> b -> c) -> [a] -> [b] -> [c]
combine f xs ys = [ f x y | x <- xs | y <- ys ]
Compiler desugars it to an application of zipWith:
combine :: (a -> b -> c) -> [a] -> [b] -> [c]
combine f xs ys = zipWith f xs ys
Which is actually what your function is, so:
combine :: (a -> b -> c) -> [a] -> [b] -> [c]
combine = zipWith
Since list comprehension usually gives Cartesian product, you can also try ZipList from Control.Applicative
GHCi> :m + Control.Applicative
GHCi> :info ZipList
newtype ZipList a = ZipList {getZipList :: [a]}
-- Defined in `Control.Applicative'
instance Functor ZipList -- Defined in `Control.Applicative'
instance Applicative ZipList -- Defined in `Control.Applicative'
GHCi> let combine f xs ys = getZipList $ f <$> ZipList xs <*> ZipList ys
GHCi> :t combine
combine :: (a2 -> a1 -> a) -> [a2] -> [a1] -> [a]
GHCi> combine (-) [10,9..] [1..10]
[9,7,5,3,1,-1,-3,-5,-7,-9]
GHCi>
Don't fear of ZipList, it just wraps a list, you can convert a list into ZipList and convert it back using getZipList.
This chapter in LYAH gives you some explanation about how to use it, have fun!
BTW, you can use a bare list in the example above, which gives you the Cartesian product:
GHCi> let combine1 f xs ys = f <$> xs <*> ys
GHCi> :t combine1
combine1 :: Applicative f => (a1 -> a -> b) -> f a1 -> f a -> f b
GHCi> combine (-) [10,9..1] [1..10]
[9,8,7,6,5,4,3,2,1,0,8,7,6,5,4,3,2,1,0,-1,...]
GHCi>
As you can see, there are two ways of merging two lists together, one is to think elements in a list as possible results, if you take one possible value from xs=[1,2], and another possible value from ys=[3,4] to make a tuple, you will end up with all possibilities: [(1,3),(1,4),(2,3),(2,4)], this is basically what [(x,y)| x <- xs, y <-ys] is saying. But there is also another way of merging two lists: every time you take one element simultaneously from two lists, and make a pair, until one of the list reaches its end, this is how ZipList get merged together.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With