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)

add :: a -> a -> a
zero :: a

sum :: [a] -> a

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

add (Gallon x) (Gallon y) = Gallon \$ x + y
zero = Gallon 0

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...