(+)
Mog 给出了一个答案,它利用了关联、交换和逆的事实。但是,我认为给出一个适用于任何操作的答案也是建设性的;也就是说,要生成要求和的实际列表,然后将它们求和。所以计划会是这样的:
- 编写一个在每个可能位置拆分列表的函数。
- 编写一个函数,通过在拆分处删除元素将拆分回列表。
- 编写一个对列表求和的函数(已经完成
Prelude
:使用该sum
函数)。
- 编写一个函数来组合它们,并包含整个列表的特殊情况。
第一部分有几种方法。第一种选择是显式递归:
splits :: [a] -> [([a], [a])]
splits [] = [([],[])]
splits (x:xs) = ([],x:xs) : map (\(b,e) -> (x:b,e)) (splits xs)
我们可以在 ghci 中检查它以确保我们做对了:
*Main> splits "abcde"
[("","abcde"),("a","bcde"),("ab","cde"),("abc","de"),("abcd","e"),("abcde","")]
但是,有一个更好的方法。该Data.List
模块包含一系列用于以特定方式修改列表的功能。其中两个是tails
和inits
:
*Main> tails "abcde"
["abcde","bcde","cde","de","e",""]
*Main> inits "abcde"
["","a","ab","abc","abcd","abcde"]
所以这个定义看起来更好看:
splits xs = zip (inits xs) (tails xs)
现在,我们需要一个函数来生成列表列表,其中每个位置删除一个元素。
dropEach xs = [beginning ++ end | (beginning, ignored:end) <- splits xs]
所以最后一步是将所有东西放在一起。
funnySums xs = map sum (xs : dropEach xs)
我们可以测试:
*Main> funnySums [1, 10, 100, 1000, 10000]
[11111,11110,11101,11011,10111,1111]