import Data.Function ((&)) import Text.Printf data SaleSum = SaleSum { totalCost :: Double, totalQuantity :: Int } class SaleSummary s where summary :: s -> SaleSum instance Semigroup SaleSum where (SaleSum c1 q1) <> (SaleSum c2 q2) = SaleSum (c1 + c2) (q1 + q2) instance Monoid SaleSum where mempty = SaleSum 0.0 0 instance Show SaleSum where show (SaleSum cost quantity) = "Total cost = " ++ printf "%.2f" cost ++ ", quantity = " ++ show quantity totalSummary :: SaleSummary s => [s] -> SaleSum totalSummary xs = xs & map summary & mconcat ---------------------------------------------------------------- data Sale = Sale { itemID :: String, price :: Double, quantity :: Int -- maybe some other fields } instance SaleSummary Sale where summary s = SaleSum (price s * fromIntegral (quantity s)) (quantity s) testSales = [ Sale "Foo" 0.20 4, Sale "Bar" 1.10 3 ] main = print $ totalSummary testSales