-- 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 7.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
-- | 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.Process m => CRDT.LamportClock.Process (Control.Monad.Trans.Reader.ReaderT r 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.
--
--
-- - Payload Internal state of a replica.
-- - Intent User's request to update.
-- - Operation (Op) Operation to be applied to other
-- replicas.
--
--
-- 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
-- |
-- - id of previous vertex, Nothing means the beginning
-- - atom
-- - id of this vertex
--
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 s = LamportClockSimT s Identity
-- | Lamport clock simulation. Key is Pid. Non-present value is
-- equivalent to (0, initial).
newtype LamportClockSimT s m a
LamportClockSim :: (ExceptT String (RWST s () (Map Pid (ProcessState s)) m) a) -> LamportClockSimT s m a
type ProcessSim s = ProcessSimT s Identity
-- | ProcessSim inside Lamport clock simulation.
newtype ProcessSimT s m a
ProcessSim :: (ReaderT Pid (LamportClockSimT s m) a) -> ProcessSimT s m a
runLamportClockSim :: s -> LamportClockSim s a -> Either String a
runLamportClockSimT :: Monad m => s -> LamportClockSimT s m a -> m (Either String a)
runProcessSim :: Pid -> ProcessSim s a -> LamportClockSim s a
runProcessSimT :: Pid -> ProcessSimT s m a -> LamportClockSimT s m a
instance GHC.Base.Monad m => Control.Monad.Fail.MonadFail (CRDT.LamportClock.Simulation.ProcessSimT s m)
instance GHC.Base.Monad m => GHC.Base.Monad (CRDT.LamportClock.Simulation.ProcessSimT s m)
instance GHC.Base.Functor m => GHC.Base.Functor (CRDT.LamportClock.Simulation.ProcessSimT s m)
instance GHC.Base.Monad m => GHC.Base.Applicative (CRDT.LamportClock.Simulation.ProcessSimT s m)
instance GHC.Base.Monad m => Control.Monad.Error.Class.MonadError GHC.Base.String (CRDT.LamportClock.Simulation.LamportClockSimT s m)
instance GHC.Base.Monad m => GHC.Base.Monad (CRDT.LamportClock.Simulation.LamportClockSimT s m)
instance GHC.Base.Functor m => GHC.Base.Functor (CRDT.LamportClock.Simulation.LamportClockSimT s m)
instance GHC.Base.Monad m => GHC.Base.Applicative (CRDT.LamportClock.Simulation.LamportClockSimT s m)
instance Control.Monad.Trans.Class.MonadTrans (CRDT.LamportClock.Simulation.ProcessSimT s)
instance GHC.Base.Monad m => CRDT.LamportClock.Process (CRDT.LamportClock.Simulation.ProcessSimT s m)
instance GHC.Base.Monad m => CRDT.LamportClock.Clock (CRDT.LamportClock.Simulation.ProcessSimT s m)
instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState s (CRDT.LamportClock.Simulation.ProcessSimT s m)
instance Control.Monad.Trans.Class.MonadTrans (CRDT.LamportClock.Simulation.LamportClockSimT s)
instance GHC.Base.Monad m => Control.Monad.Fail.MonadFail (CRDT.LamportClock.Simulation.LamportClockSimT s 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:
--
--
-- - commutativity
x <> y == y <>
-- x
-- - idempotency
x <> x == x
--
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