hanshoglund / average

Provides a (fake) monoid for calculating arithmetic means.
BSD 3-Clause "New" or "Revised" License
1 stars 4 forks source link

What is the reason to store a list of values, instead of a running-sum/count pair? #3

Open leftaroundabout opened 7 years ago

leftaroundabout commented 7 years ago

The list monoid has the annoying property of being inefficient (caching concerns aside) when left-mappended in a long chain. This is particularly annoying since that's the way the Writer monad combines values.

The following definition should be equivalent to the current one as far as the intended use is concerned, and has no such problem:

data Average a = Average { weight :: Int
                         , averageAcc :: a
                         }

instance Num a -- or better: VectorSpace a
               => Monoid (Average a) where
  mempty = Average 0 0
  mappend (Average w₀ a₀) (Average w₁ a₁) = Average (w₀+w₁) (a₀+a₁)

average :: Fractional a => Average a -> a
average (Average w a) = a / fromIntegral w

Note that this does not interfere with the functor instance: the extra constraint is really only needed – and rightly so! – for Monoid. About Applicative I'm not sure, but I think this should also work somehow.

Is it really sensible to copy list's Applicative instance anyway, for that matter?

leftaroundabout commented 7 years ago

The Applicative instance should probably be

instance Applicative Average where
  pure = Average 1
  Average w₀ a₀ <*> Average w₁ a₁ = Average (w₀*w₁) (a₀ a₁)
eborden commented 6 years ago

The problem with pure = Average 1 is that it causes extremely confusing results when utilizing this instance. I do not think Applicative is an appropriate instance for this monoid.

leftaroundabout commented 6 years ago

@eborden you may be right, I also don't subscribe to making every type an instance of every class just because it's possible. Although pure = Average 1 by itself seems perfectly intuitive to me; do you have any particular example of confusing results that would arise from the instance I proposed?

eborden commented 6 years ago

I'm going to move the conversation about the Applicative instance to #4