diff --git a/Amount.hs b/Amount.hs new file mode 100644 index 000000000..9406c1c33 --- /dev/null +++ b/Amount.hs @@ -0,0 +1,114 @@ +module Amount +where +import Utils +import BasicTypes + +{- +a simple amount is a currency, quantity pair: + + $1 + £-50 + EUR 3.44 + GOOG 500 + 1.5h + 90m + 0 + +a mixed amount is one or more simple amounts: + + $50, EUR 3, AAPL 500 + 16h, $13.55, oranges 6 + +arithmetic: + + $1 - $5 = $-4 + $1 + EUR 0.76 = $2 + EUR0.76 + $1 = EUR 1.52 + EUR0.76 - $1 = 0 + ($5, 2h) + $1 = ($6, 2h) + ($50, EUR 3, AAPL 500) + ($13.55, oranges 6) = $67.51, AAPL 500, oranges 6 + ($50, EUR 3) * $-1 = $-53.96 + ($50, AAPL 500) * $-1 = error + +-} + +tests = runTestTT $ test [ + show (dollars 1) ~?= "$1.00" + , + show (hours 1) ~?= "1h" -- currently h1.00 + , + parseAmount "$1" ~?= dollars 1 -- currently 0 + ] + +-- currency + +data Currency = Currency { + symbol :: String, + rate :: Double -- relative to the dollar + } deriving (Eq,Show) + +currencies = + [ + Currency "$" 1 + ,Currency "EUR" 0.760383 + ,Currency "£" 0.512527 + ,Currency "h" 60 -- hours + ,Currency "m" 1 -- minutes + ] + +getcurrency :: String -> Currency +getcurrency s = head $ [(Currency symbol rate) | (Currency symbol rate) <- currencies, symbol==s] + +-- convenience +dollars = Amount $ getcurrency "$" +euro = Amount $ getcurrency "EUR" +pounds = Amount $ getcurrency "£" +hours = Amount $ getcurrency "h" +minutes = Amount $ getcurrency "m" + +conversionRate :: Currency -> Currency -> Double +conversionRate oldc newc = (rate newc) / (rate oldc) + + +-- amount + +data Amount = Amount { + currency :: Currency, + quantity :: Double + } deriving (Eq) + +instance Show Amount where show = showAmountRoundedOrZero + +nullamt = dollars 0 + +parseAmount :: String -> Amount +parseAmount s = nullamt + +showAmountRoundedOrZero :: Amount -> String +showAmountRoundedOrZero (Amount cur qty) = + let rounded = printf "%.2f" qty in + case rounded of + "0.00" -> "0" + "-0.00" -> "0" + otherwise -> (symbol cur) ++ rounded + +instance Num Amount where + abs (Amount c q) = Amount c (abs q) + signum (Amount c q) = Amount c (signum q) + fromInteger i = Amount (getcurrency "$") (fromInteger i) + (+) = amountAdd + (-) = amountSub + (*) = amountMul +Amount ac aq `amountAdd` b = Amount ac (aq + (quantity $ toCurrency ac b)) +Amount ac aq `amountSub` b = Amount ac (aq - (quantity $ toCurrency ac b)) +Amount ac aq `amountMul` b = Amount ac (aq * (quantity $ toCurrency ac b)) + +toCurrency :: Currency -> Amount -> Amount +toCurrency newc (Amount oldc q) = + Amount newc (q * (conversionRate oldc newc)) + + +-- mixed amounts + +--data MixedAmount = MixedAmount [Amount] deriving (Eq,Ord) +