Haskell: 具有长度、求和、列表平方和的累加器

Haskell: accumulator with length, summation, summation of square of a list

我是 Haskell 的新手,正在尝试使用累加器实现一个功能,但不知道如何正确使用它。

这是一个使用数字列表的函数,return 一个三元组(Int,Int,Int),使用内置的列表的长度,总和和平方和功能:

stats1 :: [Int] -> (Int,Int,Int)
stats1 xs = (length xs, sum xs, sumsq xs)

sumsq :: [Int] -> Int
sumsq [] = 0
sumsq (x:xs) = (^2) x + sumsq xs

但是,当我尝试使用累加器方式时:

stats2 :: [Int] -> (Int,Int,Int)
stats2 [] = (0,0,0)
stats2 (x:xs) = (len+1, acc+x, sumsquare + x*x ) (stats2 xs)
  where len = 0
        acc  = 0
        sumsquare = 0

我收到错误消息:

Couldn't match expected type ‘(Int, Int, Int) -> (Int, Int, Int)’
                with actual type ‘(Integer, Int, Int)’
    The function ‘(len + 1, acc + x, sumsquare + x * x)’
    is applied to one argument,
    but its type ‘(Integer, Int, Int)’ has none
    In the expression:
      (len + 1, acc + x, sumsquare + x * x) (stats2 xs)
    In an equation for ‘stats2’:
        stats2 (x : xs)
          = (len + 1, acc + x, sumsquare + x * x) (stats2 xs)
          where
              len = 0
              acc = 0
              sumsquare = 0

如何使用累加器实现与 stats1 相同的目标?谢谢。

要使用这种传递累加器的样式,您首先需要声明一个采用额外累加参数的递归函数。这可以在 where 子句中完成,在我的示例中使用 recurse。在 recurse 的初始调用中,元组用 (0,0,0) 初始化。在每一步(recurse 的第二个模式)中,值被累加,基本情况(recurse 的第一个模式)returns 结果元组。

stats2 :: [Int] -> (Int,Int,Int)
stats2 l = recurse l (0,0,0) where
        recurse [] tuple = tuple
        recurse (x:xs) (lenr,sumr,sumsq) = recurse xs (lenr+1, sumr+x, sumsq + x*x )

致电:

> stats3 [1,2,3]
(3,6,14)

您尝试的问题是您尝试使用元组作为附加参数递归调用 stats2,但您将其翻转过来,因此元组是该构造中的实际函数(需要没有参数,因此出现错误消息)。此外,如果这行得通,则在每个步骤 基本情况下,这些值将被初始化为零。

累加器是必须传递给函数的变量。

stats_h :: (Int, Int, Int) -> [Int] -> (Int, Int, Int)
stats_h p [] = p
stats_h (len, sum, sumsq) (x:xs) =
  stats_h (len+1, sum + x, sumsq + x*x) xs
 
stats :: [Int] -> (Int, Int, Int)
stats = stats_h (0, 0, 0)
λ stats_h (0, 0, 0) [1, 2, 3]
(3,6,14)
λ stats [1, 2, 3]
(3,6,14)