[Haskell-beginners] Averaging a string of numbers

Brent Yorgey byorgey at seas.upenn.edu
Sun Dec 11 16:19:05 CET 2011


On Sat, Dec 10, 2011 at 07:21:58PM -0800, goodman.m.w at gmail.com wrote:
> Hi beginners list,
> 
> I want to take a string of numbers and return the average. It is a
> string because I expect the input to be from STDIN or a file. I would
> like it to handle infinite lists. Further, I create the Stats data
> structure because later I will add support for other statistics, like
> max, min, sum, prod, etc. The following code works, but I'm not sure
> it's the proper way to do things in Haskell. For instance, maybe I
> could use a fold method instead of the explicit recursion in
> getStats?

You could indeed implement getStats with a fold, but we can even do
one better.

> -- avg.hs
> -- sm is sum, len is number of elements
> data Stats = Stats { sm :: Double, len :: Int } deriving Show

Let's add a Monoid instance for Stats, which specifies how two Stats
objects should be combined:

  instance Monoid Stats where
    mempty = Stats 0 0
    mappend (Stats sm1 len1) (Stats sm2 len2) = Stats (sm1 + sm2) (len1 + len2)

We also specify how to create a default Stats object:

  mkStats x = Stats x 1

Now getStats is simply:

  getStats :: [Double] -> Stats
  getStats = mconcat . map mkStats

That is, create a default Stats object from each list element, then
combine/summarize them all using the Monoid instance.

Other than that your code looks good to me.

-Brent



More information about the Beginners mailing list