-- 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 3.0 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.Base.Set a) module CRDT.LamportClock -- | Unique process identifier newtype Pid Pid :: Int -> Pid data LamportTime LamportTime :: !LocalTime -> !Pid -> LamportTime getTime :: Process LamportTime advance :: LamportTime -> Process () -- | Key is Pid. Non-present value is equivalent to 0. newtype LamportClock a LamportClock :: (State (IntMap LocalTime) a) -> LamportClock a runLamportClock :: LamportClock a -> a newtype Process a Process :: (ReaderT Pid LamportClock a) -> Process a getPid :: Process Pid runProcess :: Pid -> Process a -> LamportClock a instance GHC.Base.Monad CRDT.LamportClock.Process instance GHC.Base.Functor CRDT.LamportClock.Process instance GHC.Base.Applicative CRDT.LamportClock.Process instance GHC.Base.Monad CRDT.LamportClock.LamportClock instance GHC.Base.Functor CRDT.LamportClock.LamportClock instance GHC.Base.Applicative CRDT.LamportClock.LamportClock instance GHC.Show.Show CRDT.LamportClock.LamportTime 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 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 => a -> ORSet a -> Process (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.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.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.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 module CRDT.Cm -- | Partial order for causal semantics. Values of some type may be ordered -- and causally-ordered different ways. class CausalOrd a -- | x affects y means that x must go before -- y and y can not go before x. affects :: 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 Intent op type Payload op type Intent op = op makeOp i _ = Just $ pure i 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 => Intent op -> Payload op -> Maybe (Process 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) => Intent op -> Payload op -> Maybe (Process op) -- | Apply an update to the payload. An invalid update must be ignored. apply :: CmRDT op => op -> Payload op -> Payload op -- | Not comparable, i. e. ¬(a ≤ b) ∧ ¬(b ≤ a). concurrent :: CausalOrd a => a -> a -> Bool 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 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) -- | 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.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 :: a -> Process (LWW a) -- | Change state as CvRDT operation. Current value is ignored, because new -- timestamp is always greater. assign :: a -> LWW a -> Process (LWW a) -- | Query state query :: LWW a -> a advanceFromLWW :: LWW a -> Process () 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.LwwElementSet newtype LwwElementSet a LES :: (Map a (LWW Bool)) -> LwwElementSet a add :: Ord a => a -> LwwElementSet a -> Process (LwwElementSet a) initial :: LwwElementSet a lookup :: Ord a => a -> LwwElementSet a -> Bool remove :: Ord a => a -> LwwElementSet a -> Process (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)