2014-01-27 4 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

Поскольку список понимание обычно дает декартово произведение, вы также можете попробовать ZipList из 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> 

Не страх ZipList, это просто заворачивает список, вы можете преобразовать список в ZipList и преобразовать его обратно с помощью getZipList. This chapter в LYAH дает вам некоторое объяснение о том, как его использовать, получайте удовольствие!

Кстати, вы можете использовать голый список в приведенном выше примере, который дает вам декартово произведение:

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 объединяются.

Смежные вопросы