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

问题描述

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

这是一个使用数字列表的函数,并使用内置函数返回一个包含列表长度、总和和平方和的三元组 (Int,Int,Int):

stats1 :: [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)
stats2 [] = (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)’
                with actual type ‘(Integer,Int)’
    The function ‘(len + 1,acc + x,sumsquare + x * x)’
    is applied to one argument,but its type ‘(Integer,Int)’ has none
    In the expression:
      (len + 1,sumsquare + x * x) (stats2 xs)
    In an equation for ‘stats2’:
        stats2 (x : xs)
          = (len + 1,sumsquare + x * x) (stats2 xs)
          where
              len = 0
              acc = 0
              sumsquare = 0

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

解决方法

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

stats2 :: [Int] -> (Int,Int,Int)
stats2 l = recurse l (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,但是您反过来了,因此该元组是该构造中的实际函数(它不带参数) ,因此出现错误消息)。此外,如果这行得通,值将在每个步骤中用零初始化基本情况。

,

Accumulator 是一个必须传递给函数的变量。

stats_h :: (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)
stats = stats_h (0,0)
λ stats_h (0,0) [1,14)
λ stats [1,14)