在Haskell中乘以列表

Wal*_*rty 2 haskell

如何实现一个函数,将列表中的每个元素乘以另一个列表中的相应元素?例如,给定列表[1, 2, 3][4, 5, 6]返回[4, 10, 18]?我的代码如下:

calcArea :: [Int] -> [Int] -> [Int]
calcArea length width = length * width
Run Code Online (Sandbox Code Playgroud)

For*_*Bru 8

这是一个经典的用例zipWith:

calcArea = zipWith (*)
Run Code Online (Sandbox Code Playgroud)

或者,这可能更容易理解,但相当于:

calcArea length width = zipWith (*) length width
Run Code Online (Sandbox Code Playgroud)


AJF*_*mar 7

@ForceBru已经写了一个非常好的答案,但我想探索如何自己编写这种功能.

首先,我们可以编写类型签名.你已经有了:

calcArea :: [Int] -> [Int] -> [Int]
Run Code Online (Sandbox Code Playgroud)

所以现在我们可以写出两个参数可以采用的四种不同情况:

calcArea []     []     = -- TODO: case 1
calcArea (a:as) []     = -- TODO: case 2
calcArea []     (b:bs) = -- TODO: case 3
calcArea (a:as) (b:bs) = -- TODO: case 4
Run Code Online (Sandbox Code Playgroud)

第一种情况很简单:

calcArea [] [] = []
Run Code Online (Sandbox Code Playgroud)

但第二个和第三个更难.在这里,我将决定'截断'列表,这样做calcArea [1,2,3] [] = [].此外,这意味着与相同大小的列表一起使用.如果这不是函数的行为方式,您可能想要更改此项.(请注意,这是多么zipWith的行为.)另外,因为我们不指列表的元素,我们可以写_,而不是(a:as)(b:bs)像以前.

calcArea _ [] = []
calcArea [] _ = []
Run Code Online (Sandbox Code Playgroud)

(另请注意,这些情况与第一种情况重叠,因此我们可以完全删除第一种情况)

最后,我们有案例4.显然我们想a * b在一些列表中,所以让我们从那开始:

calcArea (a:as) (b:bs) = (a * b) : --???
Run Code Online (Sandbox Code Playgroud)

在这一点上,我们认识到,calcArea as bs是前两个因素的乘积asbs,然后calcArea列表的休息!也就是说,calcArea [1,2,3] [4,5,6] = (1 * 4) : calcArea [2,3] [5,6].所以我们可以重复:

calcArea (a:as) (b:bs) = (a * b) : calcArea as bs
Run Code Online (Sandbox Code Playgroud)

所以,完整的功能是:

calcArea :: [Int] -> [Int] -> [Int]
calcArea [] _ = []
calcArea _ [] = []
calcArea (a:as) (b:bs) = (a * b) : calcArea as bs
Run Code Online (Sandbox Code Playgroud)

请注意,这相当于 calcArea = zipWith (*)

我希望这有助于您将来在Haskell中编写更复杂的函数.

  • 你的意思是“产品”,而不是“总和”。----顺便说一句,我有时喜欢这种说明性(归纳?)编程,当我们从 `calcArea [1,2,3] [4,5,6] = (1 * 4) : calcArea [2,3] [ 5,6]` 到 `calcArea (one:two_three) (four:five_six) = (one * Four) : calcArea two_three Five_six`。 (2认同)