{-# LANGUAGE NamedFieldPuns #-}
module CRDT.Cv.PNCounter
( PNCounter (..)
, initial
, query
, decrement
, increment
) where
import Data.Semigroup (Semigroup (..))
import Data.Semilattice (Semilattice)
import CRDT.Cv.GCounter (GCounter)
import qualified CRDT.Cv.GCounter as GCounter
data PNCounter a = PNCounter
{ positive :: !(GCounter a)
, negative :: !(GCounter a)
}
deriving (Eq, Show)
instance Ord a => Semigroup (PNCounter a) where
PNCounter p1 n1 <> PNCounter p2 n2 = PNCounter (p1 <> p2) (n1 <> n2)
instance Ord a => Semilattice (PNCounter a)
query :: Num a => PNCounter a -> a
query PNCounter{positive, negative} =
GCounter.query positive - GCounter.query negative
decrement
:: Num a
=> Word
-> PNCounter a
-> PNCounter a
decrement i pnc@PNCounter{negative} =
pnc{negative = GCounter.increment i negative}
increment
:: Num a
=> Word
-> PNCounter a
-> PNCounter a
increment i pnc@PNCounter{positive} =
pnc{positive = GCounter.increment i positive}
initial :: PNCounter a
initial = PNCounter{positive = GCounter.initial, negative = GCounter.initial}