【问题标题】:Haskell Function for Products of Adjacent Elements in List [duplicate]列表中相邻元素乘积的 Haskell 函数
【发布时间】:2020-05-21 22:20:47
【问题描述】:

我正在尝试创建一个 Haskell 函数,其中输入是整数列表,输出是所述列表中相邻元素乘积的新列表。这是我当前的代码:

productsList :: [Integer] -> [Integer]
productsList [] = []
productsList (x:[]) = []
productsList (x:y:xs) = [x * y] ++ productsList xs

但是,当我在 GHC 中检查它时,虽然它编译得很好,但输出是错误的。例如,当我尝试: productsList [1..3],输出为:[2],这显然只是列表中前两个元素的乘积(这里的正确答案应该是[2, 6])在我看来,可能的问题可能在于当有 x 但没有 y 时,我的案例不包括在内,尽管我认为它已在 productsList (x:[]) = [] 行中涵盖

谁能帮我找出导致这种输出变化的原因?

【问题讨论】:

  • 什么是test xs?我认为这是productsList xs 的错字。
  • 顺便说一句,[x*y] ++ test xs 等价于(x*y) : (test xs),更简单,可以更快一些。
  • @bradrn 你是对的。谢谢,我已经编辑了 OP。

标签: list function haskell recursion


【解决方案1】:

对此有一个相当普遍的习惯用法:zip <*> tail == \xs -> zip xs (tail xs) 为您提供相邻对的列表。 (而且因为 zip 在它的第二个参数中是非严格的,它也适用于空列表。)

> zip <*> tail $ [1,2,3]
[(1,2),(2,3)]
> zip <*> tail $ []
[]

所以你的函数可以使用简单的列表理解来定义:

productsList :: [Integer] -> [Integer]
productsList xs = [x*y | (x, y) <- zip <*> tail $ xs]

【讨论】:

  • 因为我是 Haskell 的新手(以及一般的函数式编程),所以我不知道 zip!猜猜它回到了文档。这个答案很好,谢谢。
  • 如果我们要以奇特的方式来做,为什么不简单地productsList = zipWith (*) &lt;*&gt; tail
  • 我玩过zipWith 和配对列表,但我对配对非常感兴趣,我从未想过这种方法。
  • 一般来说,map (uncurry f) . (zip &lt;*&gt; g) == zipWith f &lt;*&gt; g.
【解决方案2】:

让我们逐步评估productsList [1..3]

productsList [1..3]
= productsList (1:2:[3])
= [1*2] ++ productsList [3]
= [1*2] ++ []
= [1*2]

所以这里的问题是productsList (x:y:xs) = [x * y] ++ productsList xs 根据需要将xy 相乘,然后在xs 而不是y:xs 上递归。这意味着productsList [a,b,c,d,e,f,…] 将计算[a*b,c*d,e*f,…] 而不是所需的[a*b,b*c,c*d,d*e,e*f,f*…]。要解决此问题,您需要递归 y:xs(正如我上面简要提到的)而不仅仅是 xs

productsList :: [Integer] -> [Integer]
productsList [] = []
productsList (x:[]) = []
productsList (x:y:xs) = [x * y] ++ productsList (y:xs)

现在函数的计算结果如下:

productsList [1..3]
= productsList (1:2:[3])
= [1*2] ++ productsList (2:[3])
= [1*2] ++ productsList (2:3:[])
= [1*2] ++ [2*3] ++ productsList (3:[])
= [1*2, 2*3] ++ []
= [1*2, 2*3]

【讨论】:

  • 感谢您通过评估解释它。作为函数式编程的新手,如您所说明的那样直观地看到它对我很有帮助。我要检查这个答案,因为它更符合我从代码中得到的一般想法。感谢您的深入和周到的回答!
  • 不客气@drPepper!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-25
相关资源
最近更新 更多