如何实现一个函数,将列表中每个元素乘以另一个列表中的相应元素?例如,如果列表[1, 2, 3]
和[4, 5, 6]
返回[4, 10, 18]
?我的代码如下:
calcArea :: [Int] -> [Int] -> [Int]
calcArea length width = length * width
答案 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 bs
和as
的前两个元素的产物,然后是列表其余部分的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]