使用Haskell的map函数来计算列表的总和

|| 哈斯克尔
addm::[Int]->Int
addm (x:xs) = sum(x:xs)
我能够使用
sum
函数来获取列表的总和,但是是否可以使用
map
函数来获取列表的总和?还可以使用map功能吗?     
已邀请:
        您不能真正使用ѭ2来汇总列表,因为map会独立对待每个列表元素。例如,您可以使用
map
来递增列表中的每个值,例如
map (+1) [1,2,3,4] -- gives [2,3,4,5]
实现addm的另一种方法是使用foldl:
addm\' = foldl (+) 0
    
        在这里,用
map
来定义impossible1ѭ不可能的定义:
sum\' xs  =  let { ys = 0 : map (\\(a,b) -> a + b) (zip xs ys) } in last ys
这实际上显示了如何用
map
(以及
zip
last
)来实现
scanl
,上面的等价于
foldl (+) 0 xs  ===  last $ scanl (+) 0 xs
scanl\' f z xs  =  let { ys = z : map (uncurry f) (zip ys xs) } in ys
我希望可以用
map
来计算许多事情,从而安排通过
zip
的各种信息流。 编辑:以上只是变相的
zipWith
(and18ѭ有点像
map2
):
sum\' xs  =  let { ys = 0 : zipWith (+) ys xs } in last ys
这似乎表明
scanl
foldl
更通用。     
        不能使用
map
将列表减少到其总和。该递归模式为
fold
sum :: [Int] -> Int
sum = foldr (+) 0
顺便说一句,请注意,您也可以将
map
定义为折叠:
map :: (a -> b) -> ([a] -> [b])
map f = fold (\\x xs -> f x : xs) []
这是因为ѭ29是列表上的规范递归函数。 参考文献:关于折叠的通用性和表达性的教程,Graham Hutton,J.Functional Programming 9(4):355–372,1999年7月。     
        经过一些见解之后,我不得不添加另一个答案:您无法使用
map
来获得列表的总和,但是您可以使用单声道版本
mapM
来获得总和。您所需要做的就是在
Sum
monoid(请参阅LYAHFGG)上使用
Writer
monad(请参阅LYAHFGG)。 我写了一个专门的版本,可能更容易理解:
data Adder a = Adder a Int

instance Monad Adder where
  return x = Adder x 0
  (Adder x s) >>= f = let Adder x\' s\' = f x
                      in Adder x\' (s + s\') 

toAdder x = Adder x x

sum\' xs = let Adder _ s = mapM toAdder xs in s  

main = print $ sum\' [1..100]
--5050
Adder
只是某种类型的包装,它也保留一个“运行总和”。我们可以将
Adder
变成单子,并在此完成一些工作:当执行
>>=
(又名“ bind \”)操作时,它将返回新的结果以及该结果的运行总和的值加上原始运行总和。
toAdder
函数采用一个Int并创建一个
Adder
,该参数将那个参数同时包含为包装值和运行总和(实际上,我们对该值不感兴趣,而仅对总和部分感兴趣)。然后,在
sum\'
中,
mapM
可以发挥其神奇作用:虽然它对嵌在monad中的值的作用类似于
map
,但它执行“38ѭ之类的\” monadic \“函数,并链接这些调用(它使用
sequence
进行此操作)。在这一点上,我们通过monad的“后门”了解标准
map
缺失的列表元素之间的相互作用。     
        将列表中的每个元素映射到每个输出中的元素:
let f(x) = x*x
map f [1,2,3]
这将返回正方形列表。 要汇总列表中的所有元素,请使用fold:
foldl (+) 0 [1,2,3]
+是您要应用的函数,0是初始值(0代表总和,1代表乘积等)     
        正如其他答案指出的那样,“正常”方式是使用
fold
函数之一。但是,可以用命令式语言编写类似于a49ѭ循环的内容:
sum\' [] = 0
sum\' xs = head $ until single loop xs where 
   single [_] = True
   single _ = False
   loop (x1 : x2 : xs) = (x1 + x2) : xs 
它将列表的前两个元素加在一起,直到最后得到一个元素列表,然后返回该值(使用
head
)。     
        我知道这个问题已经回答,但我想补充一下这个想法...
listLen2 :: [a] -> Int
listLen2 = sum . map (const 1)
我相信它会为列表中的每个项目返回常数1,并返回总和! 可能不是最佳的编码实践,但这是我的教授给我们学生的一个例子,似乎与这个问题很好地联系在一起。     
        
map
永远不是用来汇总容器元素的主要工具,就像螺丝刀永远不能是观看电影的主要工具一样。但是您可以使用螺丝刀来固定电影放映机。如果你真的想要,你可以写
import Data.Monoid
import Data.Foldable

mySum :: (Foldable f, Functor f, Num a)
      => f a -> a
mySum = getSum . fold . fmap Sum
当然,这很愚蠢。您可以获得更通用,可能更有效的版本:
mySum\' :: (Foldable f, Num a) => f a -> a
mySum\' = getSum . foldMap Sum
或更佳的选择是使用
sum
,因为它确实适合工作。     

要回复问题请先登录注册