使用列表推导定义zipWith的其他方法,没有辅助函数或扩展

时间:2014-05-20 15:25:40

标签: list haskell list-comprehension

我知道您可以将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,最好没有帮助函数或扩展?

1 个答案:

答案 0 :(得分:0)

如果没有zip,您必须使用一些 - 可以说是基本的 - 列表访问功能,即droptakeWhile。两者都是内置的,所以不是你想要避免的“帮助函数”:

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)]

为了使其成为线性,递归解决方案可以使用unfoldriterate等进行编码,但我认为不能使用列表推导进行编码。