Skip to content

Commit da80a60

Browse files
committed
refactor SemanticMoney module continues; sepraate NaiveTokenModel
1 parent 5015f46 commit da80a60

File tree

6 files changed

+80
-71
lines changed

6 files changed

+80
-71
lines changed

packages/spec-haskell/pkgs/semantic-money/semantic-money.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ library
2525
Money.Theory.MonetaryTypes
2626
Money.Theory.SemanticMoney
2727
Money.Theory.TokenModel
28+
Money.Theory.TokenModel.NaiveTokenModel
2829
-- other-modules:
2930
-- other-extensions:
3031
build-depends:

packages/spec-haskell/pkgs/semantic-money/src/Money/Theory/SemanticMoney.hs

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,27 @@ import Money.Theory.MonetaryTypes
2323
-- General Payment Primitives
2424
------------------------------------------------------------------------------------------------------------------------
2525

26-
-- | A monetary unit and its operators.
27-
class (MonetaryTypes'tvr mt t v fr, Eq mu) =>
28-
MonetaryUnit mt t v fr mu | mu -> mt where
29-
settle :: t -> mu -> mu
30-
settledAt :: mu -> t
31-
flowRate :: mu -> fr
32-
rtb :: mu -> t -> v
33-
34-
-- | An indexed monetary value and its 1-primitive operators.
35-
class (MonetaryUnit mt t v fr iv, u ~ MT_UNIT mt, Monoid iv, Eq iv) =>
36-
IndexedValue mt t v fr u iv | iv -> mt where
37-
shift1 :: v -> iv -> (iv, v)
38-
flow1 :: fr -> iv -> (iv, fr)
26+
-- | A monetary unit and its operators (0-primitives).
27+
class (MonetaryTypes mt, Eq mu) =>
28+
MonetaryUnit mt mu | mu -> mt where
29+
settle :: t ~ MT_TIME mt => t -> mu -> mu
30+
settledAt :: t ~ MT_TIME mt => mu -> t
31+
flowRate :: fr ~ MT_FLOWRATE mt => mu -> fr
32+
rtb :: MonetaryTypes'tvr mt t v fr => mu -> t -> v
33+
34+
-- | An indexed monetary value and its operators (1-primitives).
35+
class (MonetaryUnit mt iv, Monoid iv, Eq iv) =>
36+
IndexedValue mt iv | iv -> mt where
37+
shift1 :: v ~ MT_VALUE mt => v -> iv -> (iv, v)
38+
flow1 :: fr ~ MT_FLOWRATE mt => fr -> iv -> (iv, fr)
3939

4040
--
41-
-- polymorphic 2-primitives for indexed values
41+
-- polymorphic 2-primitives for indexed values.
4242
--
4343

4444
-- | Shift value for the left side (a) or right side (b).
4545
shift2a, shift2b ::
46-
(IndexedValue mt t v fr u a, IndexedValue mt t v fr u b) =>
46+
(MonetaryTypes'tv mt t v, IndexedValue mt a, IndexedValue mt b) =>
4747
v -> t -> (a, b) -> (a, b)
4848
shift2a v t (a, b) =
4949
let (a', v') = shift1 v (settle t a)
@@ -54,7 +54,7 @@ shift2b v t (a, b) = swap (shift2a (-v) t (b, a))
5454

5555
-- | Shifting flow for the left side (a) or right side (b).
5656
flow2a, flow2b ::
57-
(IndexedValue mt t v fr u a, IndexedValue mt t v fr u b) =>
57+
(MonetaryTypes'tr mt t fr, IndexedValue mt a, IndexedValue mt b) =>
5858
fr -> t -> (a, b) -> (a, b)
5959
flow2a dfr t (a, b) =
6060
let (b1, fr_a) = flow1 (flowRate a) (settle t mempty)
@@ -69,7 +69,7 @@ flow2b dfr t (a, b) = swap (flow2a (-dfr) t (b, a))
6969
-- 1) Left side produces error term with which right side is adjusted accordingly, and vice versa.
7070
-- 2) The adjustment must not produce new error term, or otherwise it would require recursive adjustments.
7171
align2a, align2b ::
72-
(IndexedValue mt t v fr u a, IndexedValue mt t v fr u b) =>
72+
(IndexedValue mt a, IndexedValue mt b) =>
7373
MT_UNIT mt -> MT_UNIT mt -> (a, b) -> (a, b)
7474
align2a u u' (a, b) = (a', b')
7575
where fr = flowRate a
@@ -101,17 +101,17 @@ instance MonetaryTypes mt => Semigroup (BasicParticle mt) where
101101
instance MonetaryTypes mt => Monoid (BasicParticle mt) where
102102
mempty = BasicParticle 0 0 0
103103

104-
instance MonetaryTypes'tvr mt t v fr =>
105-
MonetaryUnit mt t v fr (BasicParticle mt) where
104+
instance MonetaryTypes mt =>
105+
MonetaryUnit mt (BasicParticle mt) where
106106
settle t' a = a { bp_settled_at = t'
107107
, bp_settled_value = rtb a t'
108108
}
109109
settledAt = bp_settled_at
110110
flowRate = bp_flow_rate
111111
rtb (BasicParticle t s r) t' = r `mt_fr_mul_t` (t' - t) + s
112112

113-
instance MonetaryTypes'tvru mt t v fr u =>
114-
IndexedValue mt t v fr u (BasicParticle mt) where
113+
instance MonetaryTypes mt =>
114+
IndexedValue mt (BasicParticle mt) where
115115
shift1 x a = (a { bp_settled_value = bp_settled_value a + x }, x)
116116
flow1 r' a = (a { bp_flow_rate = r' }, r')
117117

@@ -133,8 +133,9 @@ data PDP_Member mt wp = PDP_Member
133133
type PDP_MemberMU mt wp = (PDP_Index mt wp, PDP_Member mt wp)
134134

135135
pdp_UpdateMember2 ::
136-
( IndexedValue mt t v fr u a
137-
, IndexedValue mt t v fr u wp
136+
( u ~ MT_UNIT mt, t ~ MT_TIME mt
137+
, IndexedValue mt a
138+
, IndexedValue mt wp
138139
, mu ~ PDP_MemberMU mt wp
139140
) =>
140141
u -> t -> (a, mu) -> (a, mu)
@@ -160,15 +161,15 @@ instance (MonetaryTypes mt, Semigroup wp) => Semigroup (PDP_Index mt wp) where
160161
instance (MonetaryTypes mt, Monoid wp) => Monoid (PDP_Index mt wp) where
161162
mempty = PDP_Index 0 mempty
162163

163-
instance MonetaryUnit mt t v fr wp =>
164-
MonetaryUnit mt t v fr (PDP_Index mt wp) where
164+
instance MonetaryUnit mt wp =>
165+
MonetaryUnit mt (PDP_Index mt wp) where
165166
settle t' a@(PDP_Index _ mpi) = a { pdpi_wp = settle t' mpi }
166167
settledAt (PDP_Index _ mpi) = settledAt mpi
167168
flowRate (PDP_Index _ mpi) = flowRate mpi
168169
rtb (PDP_Index _ mpi) = rtb mpi
169170

170-
instance IndexedValue mt t v fr u wp =>
171-
IndexedValue mt t v fr u (PDP_Index mt wp) where
171+
instance IndexedValue mt wp =>
172+
IndexedValue mt (PDP_Index mt wp) where
172173
shift1 x a@(PDP_Index tu mpi) = (a { pdpi_wp = mpi' }, x' `mt_v_mul_u` tu)
173174
where (mpi', x') = if tu == 0 then (mpi, 0) else shift1 (x `mt_v_div_u` tu) mpi
174175

@@ -189,8 +190,8 @@ deriving instance (MonetaryTypes mt, Eq wp) => Eq (PDP_Member mt wp)
189190
-- PDP_MemberMU as MonetaryUnit
190191
--
191192

192-
instance MonetaryUnit mt t v fr wp =>
193-
MonetaryUnit mt t v fr (PDP_MemberMU mt wp) where
193+
instance MonetaryUnit mt wp =>
194+
MonetaryUnit mt (PDP_MemberMU mt wp) where
194195
settle t' (pix, pm) = (pix', pm')
195196
where sv' = rtb (pix, pm) t'
196197
pix'@(PDP_Index _ mpi') = settle t' pix
Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
{-# LANGUAGE LambdaCase #-}
2-
module Money.Theory.TokenModel where
3-
-- containers
4-
import qualified Data.IntMap as IntMap
1+
{-# LANGUAGE FunctionalDependencies #-}
2+
module Money.Theory.TokenModel
3+
( TokenEvent (..)
4+
, TokenModel (initToken, tokenAccounts, processOneTokenEvent, processTokenEvents, isTokenSolvent)
5+
) where
56
--
67
import Money.Theory.SemanticMoney
78

@@ -14,42 +15,16 @@ data TokenEvent mt acc where
1415
MonetaryTypes'tr mt t fr =>
1516
t -> acc -> acc -> fr -> TokenEvent mt acc
1617

17-
type Account = Int
18+
class MonetaryUnit mt mu =>
19+
TokenModel mt mu acc token | token -> mu acc where
20+
initToken :: token
1821

19-
------------------------------------------------------------------------------------------------------------------------
20-
-- NaiveTokenModel
21-
------------------------------------------------------------------------------------------------------------------------
22+
tokenAccounts :: token -> [mu]
2223

23-
data NaiveTokenModel mt acc = MkNaiveTokenModel
24-
{ accounts :: IntMap.IntMap (BasicParticle mt) -- ^ accounts indexed by Int
25-
, pools :: IntMap.IntMap (PDP_Index mt (BasicParticle mt)) -- ^ pools indexed by Int
26-
}
24+
processOneTokenEvent :: token -> TokenEvent mt acc -> token
2725

28-
naiveProcessOneEvent ::
29-
MonetaryTypes mt =>
30-
NaiveTokenModel mt Account ->
31-
TokenEvent mt Account ->
32-
NaiveTokenModel mt Account
33-
naiveProcessOneEvent (MkNaiveTokenModel accs pools) = \case
34-
TransferEvent t from to amount -> go2 from to (shift2a amount t)
35-
UpdateFlowEvent t from to rate -> go2 from to (flow2a rate t)
36-
where go2 from to op =
37-
let sender = IntMap.findWithDefault mempty from accs
38-
receiver = IntMap.findWithDefault mempty from accs
39-
(sender', receiver') = op (sender, receiver)
40-
accs' = IntMap.insert from sender'
41-
$ IntMap.insert to receiver'
42-
$ accs
43-
in MkNaiveTokenModel accs' pools
26+
processTokenEvents :: token -> [TokenEvent mt acc] -> token
27+
processTokenEvents = foldl' processOneTokenEvent
4428

45-
naiveProcessEvents ::
46-
MonetaryTypes mt =>
47-
[TokenEvent mt Account] ->
48-
NaiveTokenModel mt Account
49-
naiveProcessEvents = foldl' naiveProcessOneEvent (MkNaiveTokenModel IntMap.empty IntMap.empty)
50-
51-
naiveSystemSnapshot ::
52-
MonetaryTypes'tv mt t v =>
53-
NaiveTokenModel mt Account ->
54-
IntMap.IntMap (t -> v)
55-
naiveSystemSnapshot = (rtb <$>) . accounts
29+
isTokenSolvent :: token -> Bool
30+
isTokenSolvent = (== 0) . length . (rtb <$>) . tokenAccounts
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{-# LANGUAGE LambdaCase #-}
2+
module Money.Theory.TokenModel.NaiveTokenModel where
3+
-- containers
4+
import qualified Data.IntMap.Lazy as IntMap
5+
--
6+
import Money.Theory.SemanticMoney
7+
import Money.Theory.TokenModel
8+
9+
10+
type Account = Int
11+
12+
data NaiveTokenModel mt = MkNaiveTokenModel
13+
{ accounts :: IntMap.IntMap (BasicParticle mt) -- ^ accounts indexed by Int
14+
, pools :: IntMap.IntMap (PDP_Index mt (BasicParticle mt)) -- ^ pools indexed by Int
15+
}
16+
17+
instance MonetaryTypes mt =>
18+
TokenModel mt (BasicParticle mt) Account (NaiveTokenModel mt) where
19+
initToken = MkNaiveTokenModel IntMap.empty IntMap.empty
20+
21+
tokenAccounts = (snd <$>) . IntMap.toList . accounts
22+
23+
processOneTokenEvent (MkNaiveTokenModel accs pools) = \case
24+
TransferEvent t from to amount -> go2 from to (shift2a amount t)
25+
UpdateFlowEvent t from to rate -> go2 from to (flow2a rate t)
26+
where go2 from to op =
27+
let sender = IntMap.findWithDefault mempty from accs
28+
receiver = IntMap.findWithDefault mempty from accs
29+
(sender', receiver') = op (sender, receiver)
30+
accs' = IntMap.insert from sender'
31+
$ IntMap.insert to receiver'
32+
$ accs
33+
in MkNaiveTokenModel accs' pools

packages/spec-haskell/pkgs/semantic-money/test/Money/Theory/SemanticMoney_prop.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ import Money.Theory.TestMonetaryTypes
1616
-- Monetary Units Laws: settle-idempotency, constant-rtb
1717
--------------------------------------------------------------------------------
1818

19-
mu_settle_idempotency :: MonetaryUnit mt t v fr mu => mu -> t -> Bool
19+
mu_settle_idempotency :: (MonetaryUnit mt mu, t ~ MT_TIME mt) => mu -> t -> Bool
2020
mu_settle_idempotency a t =
2121
settledAt (settle t a) == t &&
2222
settle t a == settle t (settle t a)
2323

24-
mu_constant_rtb :: MonetaryUnit mt t v fr mu => mu -> t -> t -> t -> Bool
24+
mu_constant_rtb :: (MonetaryUnit mt mu, t ~ MT_TIME mt) => mu -> t -> t -> t -> Bool
2525
mu_constant_rtb a t1 t2 t3 =
2626
rtb (settle t1 a) t3 == rtb a t3 &&
2727
rtb (settle t2 a) t3 == rtb a t3 &&

packages/spec-haskell/pkgs/semantic-money/test/Money/Theory/TestMonetaryTypes.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{-# LANGUAGE TypeFamilies #-}
2-
32
module Money.Theory.TestMonetaryTypes where
43
-- quickcheck
54
import Test.QuickCheck

0 commit comments

Comments
 (0)