[Haskell-beginners] Weighted average

Michael Snoyman michael at snoyman.com
Mon Nov 3 16:41:26 EST 2008


Hi everyone,

I'm trying to set up some type safe functions for doing weighted averages
and sum of products. The example I give below is to try and calculate the
average miles per gallon for a collections of vehicles. Unfortunately, I am
unable to get my weightedAverage function to work, seemingly due to an
ambiguity for which instance to use. I think that the issue is that my
"class Multiplicable" should only have two parameters, as opposed to the
three it currently has. However, I can't figure out how to get that to work.

Any help is greatly appreciated. Thank you,
Michael

----------------------------------

{-# LANGUAGE MultiParamTypeClasses #-}

import Prelude hiding (sum, product)

class Addable a where
    add :: a -> a -> a
    zero :: a

    sum :: [a] -> a
    sum = foldr add zero

class Multiplicable a b c where
    mult :: a -> b -> c

    product :: [a] -> [b] -> [c]
    product x y = map (\(x1, y1) -> x1 `mult` y1) $ zip x y

sumProduct :: (Addable c, Multiplicable a b c) => [a] -> [b] -> c
sumProduct x y = sum $ product x y

weightedAverage x y = (sumProduct y x) `divide` (sum y)

class Dividable a b c where
    divide :: c -> a -> b

newtype MilesPerGallon = MilesPerGallon Double deriving Show
newtype Gallon = Gallon Double deriving Show
newtype Mile = Mile Double deriving Show

instance Addable Gallon where
    add (Gallon x) (Gallon y) = Gallon $ x + y
    zero = Gallon 0

instance Addable Mile where
    add (Mile x) (Mile y) = Mile $ x + y
    zero = Mile 0

instance Multiplicable Gallon MilesPerGallon Mile where
    mult (Gallon x) (MilesPerGallon y) = Mile $ x * y

instance Dividable Gallon MilesPerGallon Mile where
    divide (Mile x) (Gallon y) = MilesPerGallon $ x / y

milesPerGallon :: [MilesPerGallon]
milesPerGallon = map MilesPerGallon [35, 25, 29, 20, 52]

gallons :: [Gallon]
gallons = map Gallon [500, 190, 240, 100, 600]

totalGallons :: Gallon
totalGallons = sum gallons

totalMiles :: Mile
totalMiles = sumProduct gallons milesPerGallon

totalMilesPerGallon :: MilesPerGallon
totalMilesPerGallon = totalMiles `divide` totalGallons
-- I would like some way to get the following line to replace the previous
--totalMilesPerGallon = weightedAverage milesPerGallon gallons

main = do
    putStrLn $ "Total gallons of gas used: " ++ show totalGallons
    putStrLn $ "Total miles traveled: " ++ show totalMiles
    putStrLn $ "Average miles per gallon: " ++ show totalMilesPerGallon
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/beginners/attachments/20081103/9bf23093/attachment.htm


More information about the Beginners mailing list