我正在尝试编写一个基本的递归函数来计算数字列表([1, 2, 3] -> 1 - 2 + 3
)的交替和。我是Haskell的新手,所以我一直在努力解决这个问题但收效甚微。以下是我最近的尝试。它适用于最长为2的列表。
alternateSum [] = 0
alternateSum (p:ps) = if odd (length ps) then
p - alternateSum ps
else
p + alternateSum ps
答案 0 :(得分:4)
好的 - 你不得不随身携带 sign ,所以显而易见的解决办法是用一个参数来做(然后添加一个版本来修复第一次调用的这个参数):
alternateSum' :: Num a => a -> [a] -> a
alternateSum' _ [] = 0
alternateSum' f (h:tl) = f * h + alternateSum' (-f) tl
alternateSum :: [Integer] -> Integer
alternateSum ns = alternateSum' 1 ns
将产生你想要的东西:
λ> alternateSum [1,2,3]
2
您的版本存在第一个版本的问题(假设[1,2,3]
)ps
的长度为2
,当然甚至但[1,2]
1}}它的长度为1
(奇数),你的版本是正确的...那就是你遇到麻烦的地方 - 你的标志取决于长度而不是位置
这是一个有趣的版本,您可以尝试找出:
alternateSum :: [Integer] -> Integer
alternateSum ns = sum $ zipWith ($) (cycle [id,negate]) ns
这个将首先将列表[1,2,3]
重写为[1,(-2),3]
然后sum
列表;)
答案 1 :(得分:1)
这是一个递归替代方案:
alternateSum :: [Integer] -> Integer
alternateSum xs = go False 0 xs
-- Odd Accumul Tail
where go :: Bool -> Integer -> [Integer] -> Integer
go _ acc [] = acc
go False acc (x:xs) = go True (acc + x) xs
go True acc (x:xs) = go False (acc - x) xs
我不是一个超级专家,只是尝试。
希望这有帮助
答案 2 :(得分:1)
1 - (2 - (3 - (4 - 5))) = 1 - 2 + 3 - 4 + 5
所以你可以写
alternateSum = foldr (-) 0
很好,但效率低下。双重且更高效:
import Data.List
alternateSum = foldl' (flip (-)) 0 . reverse
但无论如何,直接尾递归解决方案应该更好。