{-# language NoMonomorphismRestriction #-}

module Satchmo.Set.Op where

import Satchmo.Set.Data
import qualified Satchmo.Boolean as B
import qualified Satchmo.Counting as C

import qualified Data.Set as S
import Data.List ( tails )

import Control.Monad ( guard, forM, liftM2 )
import Control.Applicative ( (<$>), (<*>) )

null :: (Ord a, B.MonadSAT m) => Set a -> m B.Boolean
null :: forall a (m :: * -> *). (Ord a, MonadSAT m) => Set a -> m Boolean
null Set a
s = Boolean -> Boolean
B.not forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). MonadSAT m => [Boolean] -> m Boolean
B.or ( forall {k}. Set k -> [Boolean]
elems Set a
s )

equals :: (Ord a, B.MonadSAT m) => Set a -> Set a -> m B.Boolean
equals :: forall a (m :: * -> *).
(Ord a, MonadSAT m) =>
Set a -> Set a -> m Boolean
equals = forall {m :: * -> *} {k}.
(MonadSAT m, Ord k) =>
(Boolean -> Boolean -> m Boolean) -> Set k -> Set k -> m Boolean
all2 forall (m :: * -> *). MonadSAT m => Boolean -> Boolean -> m Boolean
B.equals2 

isSubsetOf :: (Ord a, B.MonadSAT m) => Set a -> Set a -> m B.Boolean
isSubsetOf :: forall a (m :: * -> *).
(Ord a, MonadSAT m) =>
Set a -> Set a -> m Boolean
isSubsetOf = forall {m :: * -> *} {k}.
(MonadSAT m, Ord k) =>
(Boolean -> Boolean -> m Boolean) -> Set k -> Set k -> m Boolean
all2 forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). MonadSAT m => Boolean -> Boolean -> m Boolean
B.implies

isSupersetOf :: (Ord a, B.MonadSAT m) => Set a -> Set a -> m B.Boolean
isSupersetOf :: forall a (m :: * -> *).
(Ord a, MonadSAT m) =>
Set a -> Set a -> m Boolean
isSupersetOf = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a (m :: * -> *).
(Ord a, MonadSAT m) =>
Set a -> Set a -> m Boolean
isSubsetOf

isSingleton :: (Ord a, B.MonadSAT m) => Set a -> m B.Boolean
isSingleton :: forall a (m :: * -> *). (Ord a, MonadSAT m) => Set a -> m Boolean
isSingleton Set a
s = do
   forall (m :: * -> *). MonadSAT m => Int -> [Boolean] -> m Boolean
C.exactly Int
1 forall a b. (a -> b) -> a -> b
$ forall {k}. Set k -> [Boolean]
elems Set a
s

isDisjoint :: (Ord a, B.MonadSAT m) => Set a -> Set a -> m B.Boolean
isDisjoint :: forall a (m :: * -> *).
(Ord a, MonadSAT m) =>
Set a -> Set a -> m Boolean
isDisjoint = forall {m :: * -> *} {k}.
(MonadSAT m, Ord k) =>
(Boolean -> Boolean -> m Boolean) -> Set k -> Set k -> m Boolean
all2 
    forall a b. (a -> b) -> a -> b
$ \ Boolean
x Boolean
y -> forall (m :: * -> *). MonadSAT m => [Boolean] -> m Boolean
B.or [ Boolean -> Boolean
B.not Boolean
x, Boolean -> Boolean
B.not Boolean
y ]

union :: (Ord a, B.MonadSAT m) => Set a -> Set a -> m (Set a)
union :: forall a (m :: * -> *).
(Ord a, MonadSAT m) =>
Set a -> Set a -> m (Set a)
union = forall {f :: * -> *} {a}.
(Ord a, MonadSAT f) =>
(Boolean -> Boolean -> f Boolean) -> Set a -> Set a -> f (Set a)
common2 forall (m :: * -> *). MonadSAT m => Boolean -> Boolean -> m Boolean
(B.||) 

intersection :: (Ord a, B.MonadSAT m) => Set a -> Set a -> m (Set a)
intersection :: forall a (m :: * -> *).
(Ord a, MonadSAT m) =>
Set a -> Set a -> m (Set a)
intersection = forall {f :: * -> *} {a}.
(Ord a, MonadSAT f) =>
(Boolean -> Boolean -> f Boolean) -> Set a -> Set a -> f (Set a)
common2 forall (m :: * -> *). MonadSAT m => Boolean -> Boolean -> m Boolean
(B.&&)

difference :: (Ord a, B.MonadSAT m) => Set a -> Set a -> m (Set a)
difference :: forall a (m :: * -> *).
(Ord a, MonadSAT m) =>
Set a -> Set a -> m (Set a)
difference = forall {f :: * -> *} {a}.
(Ord a, MonadSAT f) =>
(Boolean -> Boolean -> f Boolean) -> Set a -> Set a -> f (Set a)
common2 ( \ Boolean
x Boolean
y -> Boolean
x forall (m :: * -> *). MonadSAT m => Boolean -> Boolean -> m Boolean
B.&& (Boolean -> Boolean
B.not Boolean
y) )