haskellaccumulator

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


I am new to Haskell and am trying to implement a function with an accumulator, but don't how to correctly use it.

Here is a function using a list of numbers, and return a triple (Int, Int, Int) with length, the sum, and the sum of square of a list by using the built-in function:

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

However, when I tried to use the accumulator way:

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

I got the error message:

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

How could I achieve the same goal from stats1 using an accumulator? Thanks.


Solution

  • To use this accumulator-passing style you first need to declare a recursive function that takes the additionally accumulating parameter. This can be done in the where clause, in my example with recurse. In the initial call of recurse, the tuple is intialized with (0,0,0). In every step (second pattern of recurse), the values are accumulated, and the base case (first pattern of recurse) returns the resulting tuple.

    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 )
    

    call with:

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

    The problem with your attempt is that you try to call stats2 recursively with the tuple as an additional parameter, but you turned that around, so that the tuple is the actual function in that construct (which takes no parameters, hence the error message). Also, if this would work, the values would be initilized with zeros in every step and the base case.