packages feed

rec-def-0.1: Data/Recursive/Set.hs

{-# LANGUAGE TypeFamilies #-}
{- | The type @R (Dual Bool)@ is ike 'Bool', but allows recursive definitions:

>>> :{
  let s1 = rInsert 23 s2
      s2 = rInsert 42 s1
  in getR s1
 :}
fromList [23,42]

-}
module Data.Recursive.Set
  ( R
  , mkR
  , getR
  , module Data.Recursive.Set
  ) where

import qualified Data.Set as S
import Data.Coerce
import Data.Monoid
import Control.Monad

import Data.Recursive.R.Internal
import Data.Recursive.Propagator.Naive
import Data.Recursive.Propagator.P2

-- $setup
-- >>> :set -XFlexibleInstances
-- >>> :set -XScopedTypeVariables
-- >>> import Test.QuickCheck
-- >>> instance (Ord a, Arbitrary a) => Arbitrary (R (S.Set a)) where arbitrary = mkR <$> arbitrary
-- >>> instance (Eq a, Show a) => Show (R (S.Set a)) where show = show . getR

-- | prop> getR rEmpty === S.empty
rEmpty :: Eq a => R (S.Set a)
rEmpty = mkR S.empty

-- | prop> getR (rInsert n r1) === S.insert n (getR r1)
rInsert :: Ord a => a -> R (S.Set a) -> R (S.Set a)
rInsert x = defR1 $ lift1 $ S.insert x

-- | prop> getR (rDelete n r1) === S.delete n (getR r1)
rDelete :: Ord a => a -> R (S.Set a) -> R (S.Set a)
rDelete x = defR1 $ lift1 $ S.delete x

-- | prop> \(Fun _ p) -> getR (rFilter p r1) === S.filter p (getR r1)
rFilter :: Ord a => (a -> Bool) -> R (S.Set a) -> R (S.Set a)
rFilter f = defR1 $ lift1 $ S.filter f

-- | prop> getR (rUnion r1 r2) === S.union (getR r1) (getR r2)
rUnion :: Ord a => R (S.Set a) -> R (S.Set a) -> R (S.Set a)
rUnion = defR2 $ lift2 S.union

-- | prop> getR (rUnions rs) === S.unions (map getR rs)
rUnions :: Ord a => [R (S.Set a)] -> R (S.Set a)
rUnions = defRList $ liftList S.unions

-- | prop> getR (rIntersection r1 r2) === S.intersection (getR r1) (getR r2)
rIntersection :: Ord a => R (S.Set a) -> R (S.Set a) -> R (S.Set a)
rIntersection = defR2 $ lift2 S.intersection

-- | prop> getR (rMember n r1) === S.member n (getR r1)
rMember :: Ord a => a -> R (S.Set a) -> R Bool
rMember x = defR1 $ \ps pb -> do
    let update = do
            s <- readProp ps
            when (S.member x s) $ coerce setTop pb
    watchProp ps update
    update

-- | prop> getRDual (rNotMember n r1) === S.notMember n (getR r1)
rNotMember :: Ord a => a -> R (S.Set a) -> R (Dual Bool)
rNotMember x = defR1 $ \ps pb -> do
    let update = do
            s <- readProp ps
            when (S.member x s) $ coerce setTop pb
    watchProp ps update
    update

-- | prop> getRDual (rDisjoint r1 r2) === S.disjoint (getR r1) (getR r2)
rDisjoint :: Ord a => R (S.Set a) -> R (S.Set a) -> R (Dual Bool)
rDisjoint = defR2 $ \ps1 ps2 (PDualBool pb) -> do
    let update = do
            s1 <- readProp ps1
            s2 <- readProp ps2
            unless (S.disjoint s1 s2) $ coerce setTop pb
    watchProp ps1 update
    watchProp ps2 update
    update