@@ -1,5 +1,6 @@
1{-# LANGUAGE AllowAmbiguousTypes #-}
1{-# LANGUAGE AllowAmbiguousTypes #-}
2{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE DeriveGeneric #-}
4{-# LANGUAGE DeriveGeneric #-}
4{-# LANGUAGE KindSignatures #-}
5{-# LANGUAGE KindSignatures #-}
5{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE ScopedTypeVariables #-}
@@ -7,23 +8,27 @@
7module Data.Money.Internal ( Money(..)
8module Data.Money.Internal ( Money(..)
9 , KnownCurrency(..)
10 , KnownCurrency(..)
12import Data.Fixed (Centi)
16import Data.Fixed (Centi)
13import Data.Group
17import Data.Group
15import GHC.Generics
18import GHC.Generics
16import GHC.TypeLits
19import GHC.TypeLits
20+import GHC.Stack (HasCallStack)
18-- | Money type. This is actually 'Centi' from 'Data.Fixed' in disguise.
22-- | Money type. This is actually 'Centi' from 'Data.Fixed' in disguise.
19-- The type parameter is phantom, you probably want to use 'Currency' there.
23-- The type parameter is phantom, you probably want to use 'Currency' there.
20-- See also 'Data.Money.Currencies' for currency types.
24-- See also 'Data.Money.Currencies' for currency types.
21newtype Money curr = Money { getAmount :: Centi }
25newtype Money curr = Money { getAmount :: Centi }
22− deriving (Eq, Ord, Generic)
26+ deriving (Eq, Ord, Generic, Data)
24-- | Empty type, used only to carry its type parameter with a currency code around. E.g. 'Currency "USD"', 'Currency "GBP"', et cetera.
28-- | Empty type, used only to carry its type parameter with a currency code around. E.g. 'Currency "USD"', 'Currency "GBP"', et cetera.
25-- See Data.Money.Currencies for pre-defined currency types.
29-- See Data.Money.Currencies for pre-defined currency types.
26data Currency (name :: Symbol)
30data Currency (name :: Symbol)
31+ deriving (Generic, Data)
28-- | Statically known currency type class.
33-- | Statically known currency type class.
29class KnownCurrency c where
34class KnownCurrency c where
@@ -55,3 +60,11 @@ instance KnownCurrency c => Read (Money c) where
55 | otherwise = []
60 | otherwise = []
56 where expCurr = currencyCode @c <> " "
61 where expCurr = currencyCode @c <> " "
57 l = length expCurr
62 l = length expCurr
64+(*%) :: Money curr -> Centi -> Money curr
65+(Money m) *% pct = Money (m * pct)
67+(/%) :: HasCallStack => Money curr -> Centi -> Money curr
68+_ /% 0 = error "Called /% with 0 divisor"
69+(Money m) /% pct = Money (fromRational r)
70+ where r = toRational m / toRational pct