我已经使用递归重写了zipWith函数,现在我尝试使用列表理解来重写它。我遇到了很多绑定错误,我知道我的第二行不正确。这是我的函数,就像使用递归的zipWith一样:
zipW :: (a -> b -> c) -> [a] -> [b] -> [c]
zipW _ [] _ = []
zipW _ _ [] = []
zipW f (x:xs) (y:ys) = f x y : zipW f xs ys
这是我尝试将其重写为列表理解:
zipW2 :: (a -> b -> c) -> [a] -> [b] -> [c]
zipW2 f xs ys = [f x y | (x, y) <- zipW2 f xs ys]
我不确定如何更正第二个语句,以便它像zipWith一样工作,并允许我选择运算符。
答案 0 :(得分:2)
您需要Parallel List Comprehensions分机:
{-# LANGUAGE ParallelListComp #-}
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = [f x y | x <- xs | y <- ys]
答案 1 :(得分:0)
原始zipWith
有三种情况:
第三种情况在参数的尾部递归调用zipWith
,再次进行案例分析。
在你的定义中,你只有一个案例 - 列表理解,所以任何递归调用都会回到那个。如果没有案例分析,你可以永远循环:
>>> let myZipWith f xs ys = [ f x y | (x,y) <- myZipWith f xs ys ]
>>> myZipWith (,) [] []
^CInterrupted.
此外,因为你在递归调用中使用f
但是要求递归输出是一对,你要放置f x y
生成一对的隐式要求:< / p>
>>> :t myZipWith
myZipWith :: (t2 -> t3 -> (t2, t3)) -> t -> t1 -> [(t2, t3)]
解决方案是不递归,而是直接考虑每一对。
你可以use behzad.nouri's solution of enabling the ParallelListComp
language extension:
>>> :set -XParallelListComp
>>> let myZipWith f xs ys = [ f x y | x <- xs | y <- ys ]
>>> myZipWith (+) [1,2,4] [0,10,20]
[1,12,24]
ParallelListComp
在列表推导法律语法中生成第二个(以及后面的)垂直管道符(|
),并使用早期列表并行(类似zip)逐步执行这些列表。
很高兴知道这与正常列表理解有何不同,您可以用逗号分隔每个列表。使用逗号进行嵌套迭代,在结果列表中展平:
>>> let notZipWith f xs ys = [ f x y | x <- xs, y <- ys ]
>>> notZipWith (+) [1,2,4] [0,10,20]
[1,11,21,2,12,22,4,14,24]
Using the ParallelListComp
extension is really just syntatical sugar for the original zipWith
,所以你可能会认为这是作弊。
你也可以依靠原来的zip
:
>>> let myZipWith f xs ys = [ f x y | (x,y) <- zip xs ys ]
>>> myZipWith (+) [1,2,4] [0,10,20]
[1,12,24]
但由于zip
被定义为zipWith (,)
,因此也可能作弊。
另一种方法是使用索引:
>>> let myZipWith f xs ys = [ f x y | i <- [0..min (length xs) (length ys) - 1], let x = xs !! i, let y = ys !! i ]
>>> myZipWith (+) [1,2,4] [0,10,20]
[1,12,24]
但这会非常低效,因为!!
是一个线性时间操作,使myZipWith
成为二次,而zipWith
是线性的:
>>> :set +s
>>> last $ myZipWith (+) (replicate 10000000 1) (replicate 10000000 2)
3
(4.80 secs, 3282337752 bytes)
>>> last $ zipWith (+) (replicate 10000000 1) (replicate 10000000 2)
3
(0.40 secs, 2161935928 bytes)
我确定还有其他不好的方法可以创建具有列表理解力的zipWith
的等价物,但我并不十分相信 em 好的方式,即使是上面的方式。