-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathCommodity.hs
111 lines (97 loc) · 3.69 KB
/
Commodity.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Ledger.Commodity
( Commodity
, CommodityInfo(..), HasCommodityInfo(..)
, defaultCommodityInfo, defaultPrimaryCommodityInfo
, CommodityMap(..), HasCommodityMap(..)
, extendByDigits
) where
import Control.Lens
import Data.IntMap (IntMap, Key)
import qualified Data.IntMap as IntMap
import Data.Map (Map)
import Data.Ratio
import Data.Semigroup
import Data.Text (Text)
import Data.Thyme.Time
import Prelude hiding (lookup)
-- | Commodities are simply indices into a commodity info map, which relates
-- such commodities to the information known about them.
type Commodity = Key
extendByDigits :: Int
extendByDigits = 6
-- | All of the information known about a commodity.
data CommodityInfo = CommodityInfo
{ _commSymbol :: !Text
, _commPrecision :: !Int
, _commSuffixed :: !Bool
, _commSeparated :: !Bool
, _commThousands :: !Bool
, _commDecimalComma :: !Bool
, _commNoMarket :: !Bool
, _commBuiltin :: !Bool
, _commKnown :: !Bool
, _commPrimary :: !Bool
, _commHistory :: !(IntMap (Map UTCTime Rational))
} deriving (Eq, Read, Show)
makeClassy ''CommodityInfo
instance Semigroup CommodityInfo where
x <> y = x
& commSymbol .~ y^.commSymbol
& commPrecision .~ max (x^.commPrecision) (y^.commPrecision)
& commSuffixed .~ (x^.commSuffixed || y^.commSuffixed)
& commSeparated .~ (x^.commSeparated || y^.commSeparated)
& commThousands .~ (x^.commThousands || y^.commThousands)
& commDecimalComma .~ (x^.commDecimalComma || y^.commDecimalComma)
& commNoMarket .~ (x^.commNoMarket || y^.commNoMarket)
& commBuiltin .~ (x^.commBuiltin || y^.commBuiltin)
& commKnown .~ (x^.commKnown || y^.commKnown)
& commPrimary .~ (x^.commPrimary || y^.commPrimary)
& commHistory .~ (x^.commHistory <> y^.commHistory)
instance Monoid CommodityInfo where
mempty = defaultCommodityInfo
x `mappend` y = x <> y
-- | Return a 'CommodityInfo' with defaults selected for all fields. It is
-- intended that at least one field of the result will be modified
-- immediately.
defaultCommodityInfo :: CommodityInfo
defaultCommodityInfo = CommodityInfo
{ _commSymbol = ""
, _commPrecision = 0
, _commSuffixed = False
, _commSeparated = True
, _commThousands = True
, _commDecimalComma = False
, _commNoMarket = False
, _commBuiltin = False
, _commKnown = False
, _commPrimary = False
, _commHistory = IntMap.empty
}
defaultPrimaryCommodityInfo :: Text -> CommodityInfo
defaultPrimaryCommodityInfo sym = defaultCommodityInfo
& commSymbol .~ sym
& commPrecision .~ 2
& commNoMarket .~ True
& commKnown .~ True
& commPrimary .~ True
-- | A commodities map, relating commodity indices to information about
-- those commodities.
data CommodityMap = CommodityMap
{ _commodities :: !(IntMap CommodityInfo)
}
deriving (Eq, Read, Show)
makeClassy ''CommodityMap
instance Semigroup CommodityMap where
CommodityMap x <> CommodityMap y =
CommodityMap (IntMap.unionWith (<>) x y)
instance Monoid CommodityMap where
mempty = CommodityMap mempty
x `mappend` y = x <> y