在Haskell中乘以列表

时间:2017-10-29 18:10:59

标签: haskell

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

calcArea :: [Int] -> [Int] -> [Int]
calcArea length width = length * width

3 个答案:

答案 0 :(得分:8)

这是zipWith的经典用例:

calcArea = zipWith (*)

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

calcArea length width = zipWith (*) length width

答案 1 :(得分:6)

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

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

calcArea :: [Int] -> [Int] -> [Int]

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

calcArea []     []     = -- TODO: case 1
calcArea (a:as) []     = -- TODO: case 2
calcArea []     (b:bs) = -- TODO: case 3
calcArea (a:as) (b:bs) = -- TODO: case 4

第一种情况很简单:

calcArea [] [] = []

但第二次和第三次更难。在这里,我将决定“截断”'列表,以便calcArea [1,2,3] [] = []。此外,这意味着与相同大小的列表一起使用。如果这不是函数应该如何表现,您可能想要更改它。 (请注意,这就是zipWith的行为方式。)另外,由于我们没有引用列表中的元素,因此我们可以编写_而不是(a:as)和{{1像以前一样。

(b:bs)

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

最后,我们有案例4.显然我们希望calcArea _ [] = [] calcArea [] _ = [] 在某个列表中,所以让我们从那开始:

a * b

此时,我们发现calcArea (a:as) (b:bs) = (a * b) : --??? calcArea as bsas的前两个元素的产物,然后是列表其余部分的bs!也就是说,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

请注意,这相当于calcArea :: [Int] -> [Int] -> [Int] calcArea [] _ = [] calcArea _ [] = [] calcArea (a:as) (b:bs) = (a * b) : calcArea as bs

我希望这可以帮助你在将来在Haskell中编写更复杂的函数。

答案 2 :(得分:4)

@ ForceBru的答案是完成这项工作的最简单方法。但是,当您需要“一对一”操作而不是组合操作时,可能有时会在列表上执行仿函数和应用操作。所以这种Control.Applicative.ZipList类型只是为了这份工作而考虑的,它可能会派上用场。

import Control.Applicative

mult121 :: Num a => [a] -> [a] -> [a]
mult121 xs ys = getZipList $ (*) <$> ZipList xs <*> ZipList ys

*Main> mult121 [1,2,3] [4,5,6]
[4,10,18]