我有一个简单的问题:
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, .....
。
谢谢!
答案 0 :(得分: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 ]
编译器将其置于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
答案 1 :(得分:2)
由于列表理解通常会提供笛卡尔积,您也可以从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
将其转换回来。
LYAH中的This chapter给你一些关于如何使用它的解释,玩得开心!
顺便说一下,你可以在上面的例子中使用一个裸列表,它给你笛卡尔积:
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]
中获取一个可能的值,则从{{获取另一个可能的值1}}要制作一个元组,你最终会得到所有可能性:ys=[3,4]
,这基本上就是[(1,3),(1,4),(2,3),(2,4)]
所说的。但是还有另一种合并两个列表的方法:每次从两个列表中同时获取一个元素,然后成对,直到其中一个列表到达其结尾,这就是[(x,y)| x <- xs, y <-ys]
合并在一起的方式。
答案 2 :(得分:0)
这将是我的糟糕回答
kk :: ( a -> b -> c) -> (a,b) -> c
kk f (x,y) = f x y
combineFunk :: (a -> b -> c) -> [a] -> [b] -> [c]
combineFunk f xs ys = [cs | (a,b) <- zip xs ys , let cs = kk f (a,b) ]