2014-01-27 92 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合併在一起的方式。