【问题标题】:How to define zipWith by using zip and list comprehension如何使用 zip 和列表理解来定义 zipWith
【发布时间】:2019-10-17 16:09:26
【问题描述】:

我正在尝试使用 zip 和列表理解来编写 zipWith 函数。应用该功能后,我需要压缩这两个列表。但是我不知道在哪里使用列表理解。

我尝试为每个列表做两个列表推导。

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = zip [f x | x <- xs] [f y | y <- ys]

我希望该功能与 zipWith 相同,但是它没有加载并给出错误:

Occurs check: cannot construct the infinite type:
        c ~ (b -> c, b -> c)
      Expected type: [c]
        Actual type: [(b -> c, b -> c)]
    • In the expression: zip [f x | x <- xs] [f y | y <- ys]
      In an equation for ‘zipWith'’:
          zipWith' f xs ys = zip [f x | x <- xs] [f y | y <- ys]

    • Relevant bindings include
        ys :: [b] (bound at tutorial5.hs:166:15)
        f :: a -> b -> c (bound at tutorial5.hs:166:10)
        zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
          (bound at tutorial5.hs:166:1)
    |
166 | zipWith' f xs ys = zip [f x | x <- xs] [f y | y <- ys]

【问题讨论】:

  • 为什么要使用zip(更具体)来实现zipWith(更通用的功能)? zip = zipWith (,).

标签: haskell zip list-comprehension zipwith


【解决方案1】:

嗯,这里有一些问题。在顶层,考虑zip :: [a] -&gt; [b] -&gt; [(a,b)] 的签名:它不可能返回[c],其中c 不是元组,所以你不希望zip 成为外部函数调用你的新zipWith。您的类型错误是由 GHC 引起的,它注意到它需要强制 c 成为元素的元组,其元素的类型本身包含 c(因为应用于任何事物的 f 将始终具有 b -&gt; c 类型)。

您的列表推导也与map f xsmap f ys 基本相同。其中第二个无法进行类型检查,因为ys 的每个元素都是b,并且您不能将f 应用于b(它的第一个参数是a)。

您可以先压缩输入列表以获取 [(a,b)],然后使用列表推导在每一对上运行 f

zipWith' f xs ys = [f x y | (x,y) <- zip xs ys]

或者,使用 mapuncurry 而不是列表理解:

zipWith' f xs ys = map (uncurry f) $ zip xs ys

或者,使用 GHC 并行列表理解扩展 (-XParallelListComp),明确设计为模仿 zip

zipWith' f xs ys = [f x y | x <- xs | y <- ys]

如上所述,您不能真正执行zip last,因为它会产生元组。你可以做类似的事情

zipWith' f xs ys = [fx y | (fx, y) <- zip [f x | x <- xs] ys]

f 应用于第一个列表的元素(在[f x | x &lt;- xs]map f xs 中),使用第二个参数列表压缩这个部分应用函数的列表,然后将部分函数应用到它们的外部理解中对应的第二个参数,但这样做有点迂回。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多