1 {-# LANGUAGE ConstrainedClassMethods #-}
2 {-# LANGUAGE DefaultSignatures #-}
3 {-# LANGUAGE StandaloneDeriving #-}
4 {-# OPTIONS_GHC -fno-warn-orphans #-}
5 module Hcompta.Quantity where
8 import Data.Data (Data)
9 import Data.Decimal (Decimal, DecimalRaw(..), roundTo)
10 import Data.Eq (Eq(..))
11 import qualified Data.Foldable as Foldable
12 import Data.Function (flip)
13 import Data.Map.Strict (Map)
14 import qualified Data.Map.Strict as Map
15 import Data.Ord (Ord(..), Ordering(..))
16 import Data.Word (Word8)
17 import Prelude (Integer, Integral, Num(..), fromIntegral)
20 class Zero q => Quantity q
21 instance Quantity Integer
22 instance Quantity Decimal
23 instance Quantity qty => Quantity (Map unit qty)
28 quantity_null :: q -> Bool
29 default quantity_null :: Eq q => q -> Bool
30 quantity_null = (== quantity_zero)
31 quantity_sign :: Ord q => q -> Ordering
32 default quantity_sign :: Ord q => q -> Ordering
35 _ | quantity_null q -> EQ
36 _ | q < quantity_zero -> LT
39 instance Zero Integer where
41 quantity_null = (==) 0
42 instance Zero Decimal where
44 quantity_null = (==) 0
45 instance -- Map unit qty
46 Quantity qty => Zero (Map unit qty) where
47 quantity_zero = Map.empty
48 quantity_null = Foldable.all quantity_null
52 quantity_add :: q -> q -> q
53 instance Addable Integer where
55 instance Addable Decimal where
57 Decimal e (fromIntegral (n1 + n2))
58 where (e, n1, n2) = decimal_round_min d1 d2
59 instance -- Map unit qty
60 (Ord unit, Addable qty) => Addable (Map unit qty) where
61 quantity_add = Map.unionWith (flip quantity_add)
65 quantity_neg :: q -> q
66 instance Negable Integer where
68 instance Negable Decimal where
70 instance -- Map unit qty
71 Negable qty => Negable (Map unit qty) where
72 quantity_neg = Map.map quantity_neg
76 quantity_sub :: q -> q -> q
77 instance Subable Integer where
79 instance Subable Decimal where
81 instance -- Map unit qty
85 ) => Subable (Map unit qty) where
87 Map.unionWith (flip quantity_add) x (quantity_neg y)
89 -- * Type 'Decimal' (with orphan Data instance)
92 deriving instance Data Decimal
94 -- | Round the two 'DecimalRaw' values to the smallest exponent.
100 decimal_round_min d1@(Decimal e1 _) d2@(Decimal e2 _) = (e, n1, n2)
103 Decimal _ n1 = roundTo e d1
104 Decimal _ n2 = roundTo e d2