{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeOperators #-}
module Data.Type.Universe.Subset (
Subset, WitSubset(..)
, makeSubset
, intersection, union, symDiff, mergeSubset, imergeSubset
, mapSubset, imapSubset
, subsetToList
, subsetToAny, subsetToAll, subsetToNone
, emptySubset, fullSubset
) where
import Control.Applicative
import Data.Kind
import Data.Monoid (Alt(..))
import Data.Singletons
import Data.Singletons.Decide
import Data.Type.Functor.Product
import Data.Type.Predicate
import Data.Type.Predicate.Logic
import Data.Type.Predicate.Quantification
import Data.Type.Universe
newtype WitSubset f p (as :: f k) = WitSubset
{ runWitSubset :: forall a. Elem f as a -> Decision (p @@ a)
}
data Subset f :: (k ~> Type) -> (f k ~> Type)
type instance Apply (Subset f p) as = WitSubset f p as
instance (Universe f, Decidable p) => Decidable (Subset f p)
instance (Universe f, Decidable p) => Provable (Subset f p) where
prove = makeSubset @f @_ @p (\_ -> decide @p)
makeSubset
:: forall f k p (as :: f k). Universe f
=> (forall a. Elem f as a -> Sing a -> Decision (p @@ a))
-> Sing as
-> Subset f p @@ as
makeSubset f xs = WitSubset $ \i -> f i (indexSing i xs)
subsetToList
:: forall f p t. (Universe f, Alternative t)
=> (Subset f p --># Any f p) t
subsetToList xs s = getAlt $ (`ifoldMapSing` xs) $ \i _ -> Alt $ case runWitSubset s i of
Proved p -> pure $ WitAny i p
Disproved _ -> empty
subsetToAny
:: forall f p. Universe f
=> Subset f p -?> Any f p
subsetToAny xs s = idecideAny (\i _ -> runWitSubset s i) xs
emptySubset :: forall f as. (Universe f, SingI as) => Subset f Impossible @@ as
emptySubset = prove @(Subset f Impossible) sing
fullSubset :: forall f as. (Universe f, SingI as) => Subset f Evident @@ as
fullSubset = prove @(Subset f Evident) sing
subsetToNone :: forall f p. Universe f => Subset f p -?> None f p
subsetToNone xs s = idecideNone (\i _ -> runWitSubset s i) xs
imergeSubset
:: forall f k p q r (as :: f k). ()
=> (forall a. Elem f as a -> Decision (p @@ a) -> Decision (q @@ a) -> Decision (r @@ a))
-> Subset f p @@ as
-> Subset f q @@ as
-> Subset f r @@ as
imergeSubset f ps qs = WitSubset $ \i ->
f i (runWitSubset ps i) (runWitSubset qs i)
mergeSubset
:: forall f k p q r (as :: f k). ()
=> (forall a. Decision (p @@ a) -> Decision (q @@ a) -> Decision (r @@ a))
-> Subset f p @@ as
-> Subset f q @@ as
-> Subset f r @@ as
mergeSubset f = imergeSubset (\(_ :: Elem f as a) p -> f @a p)
intersection
:: forall f p q. ()
=> ((Subset f p &&& Subset f q) --> Subset f (p &&& q))
intersection _ = uncurry $ imergeSubset $ \(_ :: Elem f as a) -> decideAnd @p @q @a
union
:: forall f p q. ()
=> ((Subset f p &&& Subset f q) --> Subset f (p ||| q))
union _ = uncurry $ imergeSubset $ \(_ :: Elem f as a) -> decideOr @p @q @a
symDiff
:: forall f p q. ()
=> ((Subset f p &&& Subset f q) --> Subset f (p ^^^ q))
symDiff _ = uncurry $ imergeSubset $ \(_ :: Elem f as a) -> decideXor @p @q @a
subsetToAll
:: forall f p. Universe f
=> Subset f p -?> All f p
subsetToAll xs s = idecideAll (\i _ -> runWitSubset s i) xs
imapSubset
:: (forall a. Elem f as a -> p @@ a -> q @@ a)
-> (forall a. Elem f as a -> q @@ a -> p @@ a)
-> Subset f p @@ as
-> Subset f q @@ as
imapSubset f g s = WitSubset $ \i ->
mapDecision (f i) (g i) (runWitSubset s i)
mapSubset
:: Universe f
=> (p --> q)
-> (q --> p)
-> (Subset f p --> Subset f q)
mapSubset f g xs = withSingI xs $
imapSubset (\i -> f (indexSing i xs))
(\i -> g (indexSing i xs))