我知道您可以将zipWith
定义为zip
:
zipwith' f xs ys = [f x y | (x,y) <- zip xs ys]
但没有zip
怎么样?我在某个地方读到你可以用这样的并行列表理解来做到这一点:
zipwith' f xs ys = [f x y | x <- xs | y <- ys]
但是您必须在代码顶部添加{-# LANGUAGE ParallelListComp #-}
才能使其成为可能,因为它是一个扩展程序。
有没有其他方法可以使用列表理解来定义zipWith
,最好没有帮助函数或扩展?
答案 0 :(得分:0)
如果没有zip
,您必须使用一些 - 可以说是基本的 - 列表访问功能,即drop
和takeWhile
。两者都是内置的,所以不是你想要避免的“帮助函数”:
zipW :: (a -> b -> c) -> [a] -> [b] -> [c]
zipW f xs ys = [z | [z] <- takeWhile (not.null)
[z | [z] <- takeWhile (not.null) -- ~ map (head.head)
[ [ [c | (c:_) <- [drop i r]] -- ~ take 1 . drop i
| (r:_) <- [drop i rs]] -- ~ take 1 . drop i
| let rs = [[f x y | y<- ys] | x<- xs], i <- [0..]]]]
这会从笛卡尔积中恢复对角线,注意处理无限列表(因此,测量它们的length
是不可能的)以及有限的(因此,!!
不能使用)。
〜&GT; zipW(,)[1..4] [10 ..]
[(1,10),(2,11),(3,12),(4,13)]
〜&GT; zipW(,)[1 ..] [10..13]
[(1,10),(2,11),(3,12),(4,13)]
当然它是二次的,只要drop n
是 O(n),通常是。
如果列表保证是无限的,那么它会简化为
zipWi f xs ys = [ rs !! i !! i | let rs = [[f x y | y<- ys] | x<- xs], i <- [0..]]
因为使用!!
进行列表访问现在还可以(当然还是二次方):
〜&GT;拿4 $ zipWi(,)[0 ..] [10 ..]
[(0,10),(1,11),(2,12),(3,13)]
为了使其成为线性,递归解决方案可以使用unfoldr
,iterate
等进行编码,但我认为不能使用列表推导进行编码。