基本的Haskell递归函数

时间:2016-01-31 08:21:06

标签: haskell

我正在尝试编写一个基本的递归函数来计算数字列表([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         

3 个答案:

答案 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

但无论如何,直接尾递归解决方案应该更好。