如果我在 Haskell 中有两个大小相同的列表
list1 = [1.0,2.0,3.0]
list2 = [3.0,5.0,7.0]
Run Code Online (Sandbox Code Playgroud)
我将如何执行按元素添加来创建相同大小的第三个列表?
[4.0,7.0,10.0]
Run Code Online (Sandbox Code Playgroud)
具体来说,我想做一个这样的函数:
listAdd :: [Float] -> [Float] -> [Float]
listAdd a b
| length a /= length b = error "length mismatch"
otherwise = ????
Run Code Online (Sandbox Code Playgroud)
我不知道用什么来代替 '????'。我认为它必须涉及“地图”和某些版本的“+”,但部分评估的事情让我感到困惑,而且事实证明正确的语法难以捉摸。
编辑 1:
我以为我理解了与 cons 运算符匹配的模式,所以我接下来尝试了这个:
listAdd :: [Float] -> [Float] -> [Float]
listadd (x:xs) (y:ys) = (x+y) : listAdd xs ys
listAdd [] [] = []
listAdd _ _ = error "length mismatch"
Run Code Online (Sandbox Code Playgroud)
但还是有问题,因为
listAdd [1.0,2.0] [2.0,3.0]
Run Code Online (Sandbox Code Playgroud)
跳过有用的模式并返回错误。
编辑2:
消除错别字后,
listAdd :: [Float] -> [Float] -> [Float]
listAdd (x:xs) (y:ys) = (x+y) : listAdd xs ys
listAdd [] [] = []
listAdd _ _ = error "length mismatch"
Run Code Online (Sandbox Code Playgroud)
像宣传的那样工作。由于在我研究的早期阶段管理任意维度的张量类型超出了我的范围,因此我决定仅将其扩展到矩阵加法:
mAdd :: [[Float]] -> [[Float]] -> [[Float]]
mAdd (x:xs) (y:ys) = listAdd x y : mAdd xs ys
mAdd [] [] = []
mAdd _ _ = error "length mismatch"
Run Code Online (Sandbox Code Playgroud)
我意识到将功能联系在一起可能并不理想,因为它降低了模块化/可移植性,但它可以完成我需要它做的事情。
编辑 3:
我希望现在宣布某种程度的学习已经发生还为时过早。我现在有这个:
listCombine :: (Float -> Float -> Float) -> [Float] -> [Float] -> [Float]
listCombine f (x:xs) (y:ys) = (f x y) : listCombine f xs ys
listCombine f [] [] = []
listCombine _ _ _ = error "length mismatch"
Run Code Online (Sandbox Code Playgroud)
这可能与 zipWith 相同,除了它会为不匹配的长度提供错误。它以预期的结果处理了我扔给它的极端情况。
单独计算参数列表的长度是一个坏主意。我们通常希望消耗尽可能少的输入,同时产生尽可能多的输出。这被称为“不要强迫输入太多”,即尽可能懒惰。
在您的情况下,当我们分析两个参数时,如果一个列表为空而另一个列表不是,我们将知道长度不匹配:
listAdd :: [Float] -> [Float] -> [Float]
listAdd (x:xs) (y:ys) = (x+y) : listAdd ... ...
listAdd [] [] = []
listAdd _ _ = error "length mismatch"
Run Code Online (Sandbox Code Playgroud)
这样它甚至适用于无限列表。
与此类似的内置函数是zipWith,但它忽略了列表长度不匹配:
Prelude> zipWith(+) [1,2] [3]
[4]
Run Code Online (Sandbox Code Playgroud)
它等价于上面的定义,最后两行替换为 catch-all 子句
listAdd _ _ = []
Run Code Online (Sandbox Code Playgroud)