2014-01-27 56 views
3

我有一个简单的问题:结合功能与列表理解

combine :: (a -> b -> c) -> [a] -> [b] -> [c] 
combine f (a:as) (b:bs) = f a b : combine f as bs 
combine _ _ _  = [ ] 

这是递归的。现在我想用列表理解来解决同样的问题:

combine f (x:xs) (y:ys) = [ f x y | x <- (x:xs), y <- (y:ys) ] 

但我的问题是元素的组合。我只想结合x1 y1, x2 y2, xs ys ...而不是x1 y1, x1 y2, x1 ys, x2 y1, x2 y2, .....

谢谢!

+3

该函数更熟知为'zipWith'。你可以用一个列表理解来实现它,如下所示:'f xs ys = [f x y | (x,y)< - zip xs ys]' – fjh

+1

谢谢,现在该功能起作用! :-) – bolle

回答

7

你需要的是一个parallel list compehension。为了能够使用它,你需要指定一个ParallelListComp编译编译器:

{-# LANGUAGE ParallelListComp #-} 

combine :: (a -> b -> c) -> [a] -> [b] -> [c] 
combine f xs ys = [ f x y | x <- xs | y <- ys ] 

编译desugars它的zipWith应用:

combine :: (a -> b -> c) -> [a] -> [b] -> [c] 
combine f xs ys = zipWith f xs ys 

这实际上是你的功能是什么,所以:

combine :: (a -> b -> c) -> [a] -> [b] -> [c] 
combine = zipWith 
+2

不错,我不知道。因为它看起来非常类似'[f x y |。],所以我猜想一个很好的新方法来混淆我的同事x < - xs,y < - ys]'但是做了一些完全不同的事情:) –

2

由于列表理解通常给笛卡尔乘积,你也可以尝试从ZipListControl.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> 

不要怕ZipList,它只是包装的列表,你可以将列表转换成ZipList和使用getZipList其转换回。 This chapter在LYAH给你一些关于如何使用它的解释,玩得开心!

BTW,您可以使用在上面的例子中裸列表,它给你的笛卡尔乘积:

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> 

正如你所看到的,有合并两个列表连接起来的方式有两种,一种是认为如果您从xs=[1,2]获取一个可能的值,并且从ys=[3,4]获取另一个可能的值来创建元组,则您将最终得到所有可能性:[(1,3),(1,4),(2,3),(2,4)],这基本上是[(x,y)| x <- xs, y <-ys]所说的内容。但是还有另外一种合并两个列表的方法:每次你从两个列表中同时获取一个元素,并且创建一个元素,直到列表中的一个到达其末尾,这就是ZipList合并在一起的方式。