如何实现一个函数,将列表中的每个元素乘以另一个列表中的相应元素?例如,给定列表[1, 2, 3]和[4, 5, 6]返回[4, 10, 18]?我的代码如下:
calcArea :: [Int] -> [Int] -> [Int]
calcArea length width = length * width
Run Code Online (Sandbox Code Playgroud)
这是一个经典的用例zipWith:
calcArea = zipWith (*)
Run Code Online (Sandbox Code Playgroud)
或者,这可能更容易理解,但相当于:
calcArea length width = zipWith (*) length width
Run Code Online (Sandbox Code Playgroud)
@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是前两个因素的乘积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
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中编写更复杂的函数.