@@ -0,0 +1,51 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DeriveGeneric #-}
4+{-# LANGUAGE KindSignatures #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE TypeApplications #-}
7+module Data.Money.Internal ( Money(..)
8+ , Currency
9+ , KnownCurrency(..)
10+ ) where
11+
12+import Data.Fixed (Centi)
13+import Data.Group
14+import Data.Proxy
15+import GHC.Generics
16+import GHC.TypeLits
17+
18+newtype Money curr = Money { getAmount :: Centi }
19+ deriving (Eq, Ord, Generic)
20+
21+data Currency (name :: Symbol)
22+
23+class KnownCurrency c where
24+ currencyCode :: String
25+
26+instance KnownSymbol c => KnownCurrency (Currency c) where
27+ currencyCode = symbolVal (Proxy @c)
28+
29+instance Semigroup (Money curr) where
30+ Money a <> Money b = Money (a + b)
31+
32+instance Monoid (Money curr) where
33+ mempty = Money 0
34+
35+instance Group (Money curr) where
36+ invert (Money m) = Money (-m)
37+ Money m ~~ Money m' = Money (m - m')
38+ pow (Money m) n = Money (m * fromIntegral n)
39+
40+instance Abelian (Money curr)
41+
42+instance KnownCurrency c => Show (Money c) where
43+ show (Money x) = currencyCode @c <> " " <> show x
44+
45+instance KnownCurrency c => Read (Money c) where
46+ readsPrec p str
47+ | expCurr == take l str
48+ , [(am, rest)] <- readsPrec p (drop l str) = [(Money am, rest)]
49+ | otherwise = []
50+ where expCurr = currencyCode @c <> " "
51+ l = length expCurr