Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

combine-function with list-comprehension

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!

like image 1000
bolle Avatar asked Sep 17 '26 06:09

bolle


2 Answers

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
like image 112
Nikita Volkov Avatar answered Sep 20 '26 19:09

Nikita Volkov


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.

like image 39
Javran Avatar answered Sep 20 '26 19:09

Javran



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!