crdt 0.1 → 0.2
raw patch · 13 files changed
+65/−40 lines, 13 filesdep −derivePVP ok
version bump matches the API change (PVP)
Dependencies removed: derive
API changes (from Hackage documentation)
- CRDT.Cv: class Semigroup state => CvRDT state
- CRDT.GCounter.Cv.Internal: instance GHC.Classes.Ord a => CRDT.Cv.CvRDT (CRDT.GCounter.Cv.Internal.GCounter a)
- CRDT.LWW: instance GHC.Classes.Ord a => CRDT.Cv.CvRDT (CRDT.LWW.LWW a)
- CRDT.PNCounter.Cv.Internal: instance GHC.Classes.Ord a => CRDT.Cv.CvRDT (CRDT.PNCounter.Cv.Internal.PNCounter a)
+ CRDT.Cv: type CvRDT = Semilattice
+ CRDT.GCounter.Cv.Internal: instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (CRDT.GCounter.Cv.Internal.GCounter a)
+ CRDT.GCounter.Cv.Internal: instance GHC.Show.Show a => GHC.Show.Show (CRDT.GCounter.Cv.Internal.GCounter a)
+ CRDT.LWW: instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (CRDT.LWW.LWW a)
+ CRDT.LWW: instance GHC.Show.Show a => GHC.Show.Show (CRDT.LWW.LWW a)
+ CRDT.PNCounter.Cm: instance GHC.Enum.Bounded (CRDT.PNCounter.Cm.PNCounter a)
+ CRDT.PNCounter.Cm: instance GHC.Enum.Enum (CRDT.PNCounter.Cm.PNCounter a)
+ CRDT.PNCounter.Cm: instance GHC.Show.Show (CRDT.PNCounter.Cm.PNCounter a)
+ CRDT.PNCounter.Cv.Internal: instance GHC.Classes.Ord a => Data.Semilattice.Semilattice (CRDT.PNCounter.Cv.Internal.PNCounter a)
+ CRDT.PNCounter.Cv.Internal: instance GHC.Show.Show a => GHC.Show.Show (CRDT.PNCounter.Cv.Internal.PNCounter a)
+ Data.Semilattice: (<>) :: Semilattice a => a -> a -> a
+ Data.Semilattice: class Semigroup a => Semilattice a
+ Data.Semilattice: infixr 6 <>
Files
- crdt.cabal +2/−2
- lib/CRDT/Cm.hs +2/−0
- lib/CRDT/Cv.hs +5/−11
- lib/CRDT/GCounter/Cv.hs +2/−1
- lib/CRDT/GCounter/Cv/Internal.hs +1/−1
- lib/CRDT/LWW.hs +1/−1
- lib/CRDT/PNCounter/Cm.hs +1/−0
- lib/CRDT/PNCounter/Cv.hs +3/−2
- lib/CRDT/PNCounter/Cv/Internal.hs +1/−1
- lib/Data/Semilattice.hs +32/−0
- test/Instances/Cm.hs +5/−10
- test/Instances/Cv.hs +0/−4
- test/Main.hs +10/−7
crdt.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack name: crdt-version: 0.1+version: 0.2 synopsis: Conflict-free replicated data types description: Definitions of CmRDT and CvRDT. Implementations for some classic CRDTs. category: Distributed Systems@@ -35,6 +35,7 @@ CRDT.PNCounter.Cm CRDT.PNCounter.Cv CRDT.PNCounter.Cv.Internal+ Data.Semilattice default-language: Haskell2010 test-suite test@@ -45,7 +46,6 @@ build-depends: base >= 4.9 && < 4.10 , vector- , derive , QuickCheck , tasty , tasty-quickcheck
lib/CRDT/Cm.hs view
@@ -13,6 +13,8 @@ [Commutativity law] @'update' op1 . 'update' op2 == 'update' op2 . 'update' op1@++Idempotency doesn't need to hold. -} class CmRDT op where
lib/CRDT/Cv.hs view
@@ -1,8 +1,10 @@+{-# LANGUAGE ConstraintKinds #-}+ module CRDT.Cv ( CvRDT ) where -import Data.Semigroup (Semigroup (..))+import Data.Semilattice (Semilattice) {- | State-based, or convergent (Cv) replicated data type.@@ -12,14 +14,6 @@ Query function is not needed. State itself is exposed. In other words, @query = 'id'@. -Laws:--[commutativity]-- @x '<>' y == y '<>' x@--[idempotency]-- @x '<>' x == x@+Actually, a CvRDT is nothing more a 'Semilattice'. -}-class Semigroup state => CvRDT state+type CvRDT = Semilattice
lib/CRDT/GCounter/Cv.hs view
@@ -1,8 +1,9 @@ module CRDT.GCounter.Cv ( GCounter- , increment , initial , query+ -- * Operation+ , increment ) where import Data.Monoid ((<>))
lib/CRDT/GCounter/Cv/Internal.hs view
@@ -8,7 +8,7 @@ -- | Grow-only counter. newtype GCounter a = GCounter (Vector a)- deriving Eq+ deriving (Eq, Show) instance Ord a => Semigroup (GCounter a) where GCounter x <> GCounter y = GCounter $ Vector.zipWith max x y
lib/CRDT/LWW.hs view
@@ -19,7 +19,7 @@ { timestamp :: !Timestamp , value :: !a }- deriving (Eq, Ord)+ deriving (Eq, Ord, Show) instance Ord a => Semigroup (LWW a) where (<>) = max
lib/CRDT/PNCounter/Cm.hs view
@@ -10,6 +10,7 @@ -- | Positive-negative counter. Allows incrementing and decrementing. data PNCounter a = Increment | Decrement+ deriving (Bounded, Enum, Show) instance Num a => CmRDT (PNCounter a) where type State (PNCounter a) = a
lib/CRDT/PNCounter/Cv.hs view
@@ -2,10 +2,11 @@ module CRDT.PNCounter.Cv ( PNCounter- , decrement- , increment , initial , query+ -- * Operations+ , decrement+ , increment ) where import qualified CRDT.GCounter.Cv as GCounter
lib/CRDT/PNCounter/Cv/Internal.hs view
@@ -14,7 +14,7 @@ { positive :: !(GCounter a) , negative :: !(GCounter a) }- deriving Eq+ deriving (Eq, Show) instance Ord a => Semigroup (PNCounter a) where PNCounter p1 n1 <> PNCounter p2 n2 = PNCounter (p1 <> p2) (n1 <> n2)
+ lib/Data/Semilattice.hs view
@@ -0,0 +1,32 @@+module Data.Semilattice+ ( Semilattice+ , (<>)+ ) where++import Data.Semigroup (Semigroup)+import qualified Data.Semigroup as Semigroup++{- |+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 ('Semigroup.<>'), specialized to 'Semilattice'.+(<>) :: Semilattice a => a -> a -> a+(<>) = (Semigroup.<>)+infixr 6 <>+{-# INLINE (<>) #-}
test/Instances/Cm.hs view
@@ -1,19 +1,14 @@ {-# OPTIONS_GHC -Wno-orphans #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}- module Instances.Cm () where -import Data.DeriveTH (derives, makeArbitrary)-import Test.QuickCheck (Arbitrary, arbitrary, choose)+import Test.QuickCheck (Arbitrary, arbitrary, arbitraryBoundedEnum) import CRDT.LWW (LWW (..)) import CRDT.PNCounter.Cm (PNCounter (..)) -derives [makeArbitrary] [''PNCounter, ''LWW]--deriving instance Show (PNCounter a)+instance Arbitrary (PNCounter a) where+ arbitrary = arbitraryBoundedEnum -deriving instance Show a => Show (LWW a)+instance Arbitrary a => Arbitrary (LWW a) where+ arbitrary = Write <$> arbitrary <*> arbitrary
test/Instances/Cv.hs view
@@ -17,9 +17,5 @@ deriving instance Arbitrary a => Arbitrary (GCounter a) -deriving instance Show a => Show (GCounter a)- instance Arbitrary a => Arbitrary (PNCounter a) where arbitrary = PNCounter <$> arbitrary <*> arbitrary--deriving instance Show a => Show (PNCounter a)
test/Main.hs view
@@ -2,7 +2,7 @@ {-# LANGUAGE ScopedTypeVariables #-} import Data.Proxy (Proxy (..))-import Data.Semigroup ((<>))+import Data.Semilattice (Semilattice, (<>)) import Test.QuickCheck (Arbitrary, Small (..)) import Test.Tasty (TestTree, defaultMain, testGroup) import Test.Tasty.QuickCheck (testProperty)@@ -42,18 +42,18 @@ PncCv.query (PncCv.decrement i c) == pred (PncCv.query c) ] , testGroup "Cm"- [ cmrdtCommutativity (Proxy :: Proxy (PncCm.PNCounter Int)) ]+ [ cmrdtLaws (Proxy :: Proxy (PncCm.PNCounter Int)) ] ] lww :: TestTree lww = testGroup "LWW"- [ testGroup "Cm" [ cmrdtCommutativity (Proxy :: Proxy (LWW Int)) ]+ [ testGroup "Cm" [ cmrdtLaws (Proxy :: Proxy (LWW Int)) ] , testGroup "Cv" [ cvrdtLaws (Proxy :: Proxy (LWW Int)) ] ] -cvrdtLaws+semilatticeLaws :: forall a . (Arbitrary a, CvRDT a, Eq a, Show a) => Proxy a -> TestTree-cvrdtLaws _ = testGroup "CvRDT laws"+semilatticeLaws _ = testGroup "Semilattice laws" [ testProperty "associativity" associativity , testProperty "commutativity" commutativity , testProperty "idempotency" idempotency@@ -68,13 +68,16 @@ idempotency :: a -> Bool idempotency x = x <> x == x -cmrdtCommutativity+cvrdtLaws :: (Arbitrary a, Semilattice a, Eq a, Show a) => Proxy a -> TestTree+cvrdtLaws = semilatticeLaws++cmrdtLaws :: forall op . ( Arbitrary op, CmRDT op, Show op , Arbitrary (State op), Eq (State op), Show (State op) ) => Proxy op -> TestTree-cmrdtCommutativity _ = testProperty "CmRDT law: commutativity" commutativity+cmrdtLaws _ = testProperty "CmRDT law: commutativity" commutativity where commutativity :: op -> op -> State op -> Bool commutativity op1 op2 x =