-- 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 9.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 -- | Get sequential timestamps. -- -- Laws: 1. t1 <- getTimes n t2 <- getTime t2 >= t1 + n -- --
    --
  1. getTimes 0 == getTimes 1
  2. --
getTimes :: Clock m => Natural -> m LamportTime advance :: Clock m => LocalTime -> m () data LamportTime LamportTime :: LocalTime -> Pid -> LamportTime getTime :: Clock m => m LamportTime -- | Unix time in 10^{-7} seconds (100 ns), as in RFC 4122 and Swarm RON. type LocalTime = Natural class Monad m => Process m getPid :: Process m => m Pid data LamportClock a runLamportClock :: TVar LocalTime -> LamportClock a -> IO a getRealLocalTime :: IO LocalTime 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.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 m => CRDT.LamportClock.Clock (Control.Monad.Trans.Reader.ReaderT r m) instance CRDT.LamportClock.Clock m => CRDT.LamportClock.Clock (Control.Monad.Trans.State.Strict.StateT s m) instance CRDT.LamportClock.Process m => CRDT.LamportClock.Process (Control.Monad.Trans.Reader.ReaderT r m) instance CRDT.LamportClock.Process m => CRDT.LamportClock.Process (Control.Monad.Trans.State.Strict.StateT s m) 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. -- --

Implementation

-- -- In Haskell, a CmRDT implementation consists of 3 types — a -- payload, an operation (op) and an -- intent. -- -- -- -- For many types operation and intent may be the same. But -- for LWW, for instance, this rule doesn't hold: user can request -- only value, and type attaches a timestamp to it. -- --

Additional constraint — commutativity law

-- -- Concurrent updates are observed equally. -- --
--   ∀ 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; } initial :: CmRDT op => Payload 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 query :: forall op f. (CmRDT op, Foldable f) => f op -> Payload op -- | Make op and apply it to the payload -- a common routine at the source -- node. makeAndApplyOp :: (CmRDT op, Clock m, MonadFail m, MonadState (Payload op) m) => Intent op -> m op makeAndApplyOps :: (CmRDT op, Clock m, MonadFail m, MonadState (Payload op) m, Traversable f) => f (Intent op) -> m (f op) -- | 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) -- | Replicated Growable Array (RGA) module CRDT.Cm.RGA data RGA a -- | OpAddAfter :: (Maybe VertexId) -> a -> VertexId -> RGA a OpRemove :: VertexId -> RGA a data RgaIntent a -- | Nothing means the beginning AddAfter :: (Maybe VertexId) -> a -> RgaIntent a Remove :: VertexId -> RgaIntent a data RgaPayload a RgaPayload :: Vector (VertexId, Maybe a) -> Map VertexId Int -> RgaPayload a [vertices] :: RgaPayload a -> Vector (VertexId, Maybe a) -- | indices in vertices vector [vertexIxs] :: RgaPayload a -> Map VertexId Int fromString :: (Clock m, MonadFail m, MonadState (RgaPayload Char) m) => String -> m [RGA Char] load :: Vector (VertexId, Maybe a) -> RgaPayload a toString :: RgaPayload Char -> String toVector :: RgaPayload a -> Vector a instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cm.RGA.RGA a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cm.RGA.RGA a) instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cm.RGA.RgaIntent a) instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cm.RGA.RgaPayload a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cm.RGA.RgaPayload a) instance CRDT.Cm.CausalOrd (CRDT.Cm.RGA.RGA a) instance GHC.Classes.Ord a => CRDT.Cm.CmRDT (CRDT.Cm.RGA.RGA 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 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 CRDT.LamportClock.Simulation type LamportClockSim = LamportClockSimT Identity -- | Lamport clock simulation. Key is Pid. Non-present value is -- equivalent to (0, initial). newtype LamportClockSimT m a LamportClockSim :: (ExceptT String (StateT (Map Pid LocalTime) m) a) -> LamportClockSimT m a type ProcessSim = ProcessSimT Identity -- | ProcessSim inside Lamport clock simulation. newtype ProcessSimT m a ProcessSim :: (ReaderT Pid (LamportClockSimT m) a) -> ProcessSimT m a runLamportClockSim :: LamportClockSim a -> Either String a runLamportClockSimT :: Monad m => LamportClockSimT m a -> m (Either String a) runProcessSim :: Pid -> ProcessSim a -> LamportClockSim a runProcessSimT :: Pid -> ProcessSimT m a -> LamportClockSimT m a instance GHC.Base.Monad m => Control.Monad.Fail.MonadFail (CRDT.LamportClock.Simulation.ProcessSimT m) instance GHC.Base.Monad m => GHC.Base.Monad (CRDT.LamportClock.Simulation.ProcessSimT m) instance GHC.Base.Functor m => GHC.Base.Functor (CRDT.LamportClock.Simulation.ProcessSimT m) instance GHC.Base.Monad m => GHC.Base.Applicative (CRDT.LamportClock.Simulation.ProcessSimT m) instance GHC.Base.Monad m => Control.Monad.Error.Class.MonadError GHC.Base.String (CRDT.LamportClock.Simulation.LamportClockSimT m) instance GHC.Base.Monad m => GHC.Base.Monad (CRDT.LamportClock.Simulation.LamportClockSimT m) instance GHC.Base.Functor m => GHC.Base.Functor (CRDT.LamportClock.Simulation.LamportClockSimT m) instance GHC.Base.Monad m => GHC.Base.Applicative (CRDT.LamportClock.Simulation.LamportClockSimT m) instance Control.Monad.Trans.Class.MonadTrans CRDT.LamportClock.Simulation.ProcessSimT instance GHC.Base.Monad m => CRDT.LamportClock.Process (CRDT.LamportClock.Simulation.ProcessSimT m) instance GHC.Base.Monad m => CRDT.LamportClock.Clock (CRDT.LamportClock.Simulation.ProcessSimT m) instance Control.Monad.Trans.Class.MonadTrans CRDT.LamportClock.Simulation.LamportClockSimT instance GHC.Base.Monad m => Control.Monad.Fail.MonadFail (CRDT.LamportClock.Simulation.LamportClockSimT m) module Data.MultiMap newtype MultiMap k v MultiMap :: (Map k (Set v)) -> MultiMap k v assocs :: MultiMap k v -> [(k, [v])] delete :: (Ord k, Ord v) => k -> v -> MultiMap k v -> MultiMap k v deleteMany :: (Ord k, Ord v) => k -> Set v -> MultiMap k v -> MultiMap k v empty :: MultiMap k v insert :: (Ord k, Ord v) => k -> v -> MultiMap k v -> MultiMap k v keysSet :: MultiMap k v -> Set k -- | If no key in the map then the result is empty. lookup :: Ord k => k -> MultiMap k v -> Set v singleton :: k -> v -> MultiMap k v instance (GHC.Show.Show v, GHC.Show.Show k) => GHC.Show.Show (Data.MultiMap.MultiMap k v) instance (GHC.Classes.Eq v, GHC.Classes.Eq k) => GHC.Classes.Eq (Data.MultiMap.MultiMap k v) module CRDT.Cm.ORSet data ORSet a OpAdd :: a -> Tag -> ORSet a OpRemove :: a -> (Set Tag) -> ORSet a data Intent a Add :: a -> Intent a Remove :: a -> Intent a data Payload a Payload :: MultiMap a Tag -> Version -> Payload a [elements] :: Payload a -> MultiMap a Tag [version] :: Payload a -> Version data Tag Tag :: Pid -> Version -> Tag query :: (Ord a, Foldable f) => f (ORSet a) -> Set a instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cm.ORSet.Payload a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cm.ORSet.Payload a) instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cm.ORSet.ORSet a) instance GHC.Classes.Ord CRDT.Cm.ORSet.Tag instance GHC.Classes.Eq CRDT.Cm.ORSet.Tag instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cm.ORSet.Intent a) instance GHC.Classes.Ord a => CRDT.Cm.CmRDT (CRDT.Cm.ORSet.ORSet a) instance CRDT.Cm.CausalOrd (CRDT.Cm.ORSet.ORSet a) instance GHC.Show.Show CRDT.Cm.ORSet.Tag 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 initialize :: 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 member :: Ord a => a -> TwoPSet a -> Bool remove :: Ord a => a -> TwoPSet a -> TwoPSet a singleton :: Ord a => a -> TwoPSet a -- | XXX Internal 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.RGA -- | TODO(cblp, 2018-02-06) Vector.Unboxed newtype RGA a RGA :: [(VertexId, Maybe a)] -> RGA a fromList :: Clock m => [a] -> m (RGA a) toList :: RGA a -> [a] -- | Replace content with specified, applying changed found by the diff -- algorithm edit :: (Eq a, Clock m) => [a] -> RGA a -> m (RGA a) type RgaString = RGA Char fromString :: Clock m => String -> m RgaString toString :: RgaString -> String -- | Compact version of RGA. For each VertexId, the -- corresponding sequence of vetices has the same Pid and -- sequentially growing LocalTime, starting with the specified -- one. type RgaPacked a = [(VertexId, [Maybe a])] pack :: RGA a -> RgaPacked a unpack :: RgaPacked a -> RGA a instance GHC.Show.Show a => GHC.Show.Show (CRDT.Cv.RGA.RGA a) instance GHC.Classes.Eq a => GHC.Classes.Eq (CRDT.Cv.RGA.RGA a) instance GHC.Classes.Eq a => Data.Semigroup.Semigroup (CRDT.Cv.RGA.RGA a) instance GHC.Classes.Eq a => Data.Semilattice.Semilattice (CRDT.Cv.RGA.RGA a) instance GHC.Classes.Eq a => GHC.Base.Monoid (CRDT.Cv.RGA.RGA 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