-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Conflict-free replicated data types -- -- Definitions of CmRDT and CvRDT. Implementations for some classic -- CRDTs. @package crdt @version 5.0 module CRDT.Cv.GSet -- | Grow-only set type GSet = Set -- | update add :: Ord a => a -> GSet a -> GSet a -- | initialization initial :: GSet a -- | lookup query lookup :: Ord a => a -> GSet a -> Bool module CRDT.Cv.Max newtype Max a :: * -> * Max :: a -> Max a [getMax] :: Max a -> a -- | Construct new value initial :: a -> Max a query :: Max a -> a module CRDT.LamportClock -- | Unique process identifier newtype Pid Pid :: Word64 -> Pid class Process m => Clock m getTime :: Clock m => m LamportTime advance :: Clock m => LocalTime -> m () data LamportTime LamportTime :: !LocalTime -> !Pid -> LamportTime -- | Lamport clock simpulation. Key is Pid. Non-present value is -- equivalent to 0. newtype LamportClockSim a LamportClockSim :: (State (Map Pid LocalTime) a) -> LamportClockSim a runLamportClockSim :: LamportClockSim a -> a class Monad m => Process m getPid :: Process m => m Pid -- | ProcessSim inside Lamport clock simpulation. newtype ProcessSim a ProcessSim :: (ReaderT Pid LamportClockSim a) -> ProcessSim a runProcessSim :: Pid -> ProcessSim a -> LamportClockSim a instance Control.Monad.IO.Class.MonadIO CRDT.LamportClock.LamportClock instance GHC.Base.Monad CRDT.LamportClock.LamportClock instance GHC.Base.Functor CRDT.LamportClock.LamportClock instance GHC.Base.Applicative CRDT.LamportClock.LamportClock instance GHC.Base.Monad CRDT.LamportClock.ProcessSim instance GHC.Base.Functor CRDT.LamportClock.ProcessSim instance GHC.Base.Applicative CRDT.LamportClock.ProcessSim instance GHC.Base.Monad CRDT.LamportClock.LamportClockSim instance GHC.Base.Functor CRDT.LamportClock.LamportClockSim instance GHC.Base.Applicative CRDT.LamportClock.LamportClockSim instance GHC.Classes.Ord CRDT.LamportClock.LamportTime instance GHC.Classes.Eq CRDT.LamportClock.LamportTime instance GHC.Show.Show CRDT.LamportClock.Pid instance GHC.Classes.Ord CRDT.LamportClock.Pid instance GHC.Classes.Eq CRDT.LamportClock.Pid instance CRDT.LamportClock.Process CRDT.LamportClock.LamportClock instance CRDT.LamportClock.Clock CRDT.LamportClock.LamportClock instance CRDT.LamportClock.Clock CRDT.LamportClock.ProcessSim instance CRDT.LamportClock.Process CRDT.LamportClock.ProcessSim instance GHC.Show.Show CRDT.LamportClock.LamportTime module CRDT.Cm -- | Partial order for causal semantics. Values of some type may be ordered -- and causally-ordered different ways. class CausalOrd a -- | x precedes y means that x must go before -- y and y can not go before x. precedes :: CausalOrd a => a -> a -> Bool -- | Operation-based, or commutative (Cm) replicated data type. -- --
-- ∀ op1 op2 . -- concurrent op1 op2 ==> apply op1 . apply op2 == apply op2 . apply op1 ---- -- Idempotency doesn't need to hold. class (CausalOrd op, Eq (Payload op)) => CmRDT op where { type family Intent op; type family Payload op; type Intent op = op; } -- | Generate an update to the local and remote replicas. -- -- Returns Nothing if the intended operation is not applicable. makeOp :: (CmRDT op, Clock m) => Intent op -> Payload op -> Maybe (m op) -- | Generate an update to the local and remote replicas. -- -- Returns Nothing if the intended operation is not applicable. makeOp :: (CmRDT op, Intent op ~ op, Applicative m) => Intent op -> Payload op -> Maybe (m op) -- | Apply an update to the payload (downstream). An invalid update must be -- ignored. -- -- TODO(Syrovetsky, 2017-12-05) There is no downstream precondition yet. -- We must make a test for it first. apply :: CmRDT op => op -> Payload op -> Payload op -- | Not comparable, i. e. ¬(a ≤ b) ∧ ¬(b ≤ a). concurrent :: CausalOrd a => a -> a -> Bool -- | TODO(cblp, 2017-09-29) USet? module CRDT.Cm.TwoPSet data TwoPSet a Add :: a -> TwoPSet a Remove :: a -> TwoPSet a instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cm.TwoPSet.TwoPSet a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cm.TwoPSet.TwoPSet a) instance GHC.Classes.Ord a => CRDT.Cm.CmRDT (CRDT.Cm.TwoPSet.TwoPSet a) instance GHC.Classes.Eq a => CRDT.Cm.CausalOrd (CRDT.Cm.TwoPSet.TwoPSet a) module CRDT.Cm.GSet newtype GSet a Add :: a -> GSet a instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cm.GSet.GSet a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cm.GSet.GSet a) instance GHC.Classes.Ord a => CRDT.Cm.CmRDT (CRDT.Cm.GSet.GSet a) instance GHC.Classes.Eq a => CRDT.Cm.CausalOrd (CRDT.Cm.GSet.GSet a) module CRDT.Cm.Counter data Counter a Increment :: Counter a Decrement :: Counter a instance GHC.Show.Show (CRDT.Cm.Counter.Counter a) instance GHC.Classes.Eq (CRDT.Cm.Counter.Counter a) instance GHC.Enum.Enum (CRDT.Cm.Counter.Counter a) instance GHC.Enum.Bounded (CRDT.Cm.Counter.Counter a) instance (GHC.Num.Num a, GHC.Classes.Eq a) => CRDT.Cm.CmRDT (CRDT.Cm.Counter.Counter a) instance CRDT.Cm.CausalOrd (CRDT.Cm.Counter.Counter a) module Data.Semilattice -- | A semilattice. -- -- It may be a join-semilattice, or meet-semilattice, it doesn't matter. -- -- If it matters for you, use package lattices. -- -- In addition to Semigroup, Semilattice defines this laws: -- -- class Semigroup a => Semilattice a -- | Just (<>), specialized to Semilattice. merge :: Semilattice a => a -> a -> a infixr 6 `merge` instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (Data.Semigroup.Max a) instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (Data.Set.Internal.Set a) module CRDT.LWW -- | Last write wins. Assuming timestamp is unique. This type is both -- CmRDT and CvRDT. -- -- Timestamps are assumed unique, totally ordered, and consistent with -- causal order; i.e., if assignment 1 happened-before assignment 2, the -- former’s timestamp is less than the latter’s. data LWW a LWW :: !a -> !LamportTime -> LWW a [value] :: LWW a -> !a [time] :: LWW a -> !LamportTime -- | Initialize state initial :: Clock m => a -> m (LWW a) -- | Change state as CvRDT operation. Current value is ignored, because new -- timestamp is always greater. assign :: Clock m => a -> LWW a -> m (LWW a) -- | Query state query :: LWW a -> a advanceFromLWW :: Clock m => LWW a -> m () instance GHC.Show.Show a => GHC.Show.Show (CRDT.LWW.LWW a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.LWW.LWW a) instance GHC.Classes.Eq a => Data.Semigroup.Semigroup (CRDT.LWW.LWW a) instance GHC.Classes.Eq a => Data.Semilattice.Semilattice (CRDT.LWW.LWW a) instance CRDT.Cm.CausalOrd (CRDT.LWW.LWW a) instance GHC.Classes.Eq a => CRDT.Cm.CmRDT (CRDT.LWW.LWW a) module CRDT.Cv.TwoPSet newtype TwoPSet a TwoPSet :: (Map a Bool) -> TwoPSet a add :: Ord a => a -> TwoPSet a -> TwoPSet a initial :: TwoPSet a lookup :: Ord a => a -> TwoPSet a -> Bool remove :: Ord a => a -> TwoPSet a -> TwoPSet a singleton :: Ord a => a -> TwoPSet a -- | XXX Internal TODO remove isKnown :: Ord a => a -> TwoPSet a -> Bool instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cv.TwoPSet.TwoPSet a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cv.TwoPSet.TwoPSet a) instance GHC.Classes.Ord a => Data.Semigroup.Semigroup (CRDT.Cv.TwoPSet.TwoPSet a) instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (CRDT.Cv.TwoPSet.TwoPSet a) module CRDT.Cv.ORSet newtype ORSet a ORSet :: (Map a (Map Tag Bool)) -> ORSet a add :: (Ord a, Process m) => a -> ORSet a -> m (ORSet a) initial :: ORSet a remove :: Ord a => a -> ORSet a -> ORSet a lookup :: Ord a => a -> ORSet a -> Bool instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cv.ORSet.ORSet a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cv.ORSet.ORSet a) instance GHC.Classes.Ord a => Data.Semigroup.Semigroup (CRDT.Cv.ORSet.ORSet a) instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (CRDT.Cv.ORSet.ORSet a) module CRDT.Cv.LwwElementSet newtype LwwElementSet a LES :: (Map a (LWW Bool)) -> LwwElementSet a add :: (Ord a, Clock m) => a -> LwwElementSet a -> m (LwwElementSet a) initial :: LwwElementSet a lookup :: Ord a => a -> LwwElementSet a -> Bool remove :: (Ord a, Clock m) => a -> LwwElementSet a -> m (LwwElementSet a) instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cv.LwwElementSet.LwwElementSet a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cv.LwwElementSet.LwwElementSet a) instance GHC.Classes.Ord a => Data.Semigroup.Semigroup (CRDT.Cv.LwwElementSet.LwwElementSet a) instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (CRDT.Cv.LwwElementSet.LwwElementSet a) module CRDT.Cv.GCounter -- | Grow-only counter. newtype GCounter a GCounter :: (IntMap a) -> GCounter a -- | Initial state initial :: GCounter a -- | Get value from the state query :: Num a => GCounter a -> a -- | Increment counter increment :: Num a => Word -> GCounter a -> GCounter a instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cv.GCounter.GCounter a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cv.GCounter.GCounter a) instance GHC.Classes.Ord a => Data.Semigroup.Semigroup (CRDT.Cv.GCounter.GCounter a) instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (CRDT.Cv.GCounter.GCounter a) module CRDT.Cv.PNCounter -- | Positive-negative counter. Allows incrementing and decrementing. Nice -- example of combining of existing CvRDT (GCounter in this case) -- to create another CvRDT. data PNCounter a PNCounter :: !(GCounter a) -> !(GCounter a) -> PNCounter a [positive] :: PNCounter a -> !(GCounter a) [negative] :: PNCounter a -> !(GCounter a) -- | Initial state initial :: PNCounter a -- | Get value from the state query :: Num a => PNCounter a -> a -- | Decrement counter decrement :: Num a => Word -> PNCounter a -> PNCounter a -- | Increment counter increment :: Num a => Word -> PNCounter a -> PNCounter a instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cv.PNCounter.PNCounter a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cv.PNCounter.PNCounter a) instance GHC.Classes.Ord a => Data.Semigroup.Semigroup (CRDT.Cv.PNCounter.PNCounter a) instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (CRDT.Cv.PNCounter.PNCounter a) module CRDT.Cv -- | State-based, or convergent (Cv) replicated data type. -- -- Update is any function modifying state. -- -- Query function is not needed. State itself is exposed. In other words, -- query = id. Some types may offer more convenient query -- functions. -- -- Actually, a CvRDT is nothing more a Semilattice. type CvRDT = Semilattice