module Data.HSet ( HSet(..) , HGet(..) , HGetable , hask , SubHSet(..) , SubHSetable , hdelete , hnarrow -- * Work with 'Labeled' elements , hgetLabeled , haskLabeled -- * Reexports , module Data.HSet.Labeled ) where import Control.Monad.Reader import Data.HSet.Labeled import Data.HSet.TypeLevel import Data.Typeable #if !(MIN_VERSION_base(4, 8, 0)) import Control.Applicative #endif {- | Heterogeneous set (list) of elements with unique types. Useful with MonadReader. >>> let x = HSCons (10 :: Int) $ HSCons (20 :: Double) HSNil >>> x HSCons (10) (HSCons (20.0) (HSNil)) >>> hget x :: Int 10 >>> hget x :: Double 20.0 Note that 'hget' takes specific element from list of uniquely typed elements depending on what type is required to be returned. -} data HSet (elems :: [*]) where HSNil :: HSet '[] HSCons :: ('False ~ (Elem elem elems)) => !elem -> !(HSet elems) -> HSet (elem ': elems) deriving ( Typeable ) instance Show (HSet '[]) where show HSNil = "HSNil" instance (Show e, Show (HSet els)) => Show (HSet (e ': els)) where show (HSCons e els) = "HSCons (" ++ show e ++ ") (" ++ show els ++ ")" instance Eq (HSet '[]) where HSNil == HSNil = True instance (Eq e, Eq (HSet els)) => Eq (HSet (e ': els)) where (HSCons e els) == (HSCons e' els') = (e == e') && (els == els') instance Ord (HSet '[]) where HSNil `compare` HSNil = EQ instance (Ord e, Ord (HSet els)) => Ord (HSet (e ': els)) where (HSCons e els) `compare` (HSCons e' els') = case e `compare` e' of EQ -> els `compare` els' x -> x -- | Typeclass for sets and elements. class (i ~ (Index e els)) => HGet els e i where -- | Gets any data from HSet for you hget :: HSet els -> e instance HGet (e ': els) e 'Z where hget (HSCons e _) = e instance (i ~ (Index e els), ('S i) ~ (Index e (e1 ': els)), HGet els e i) => HGet (e1 ': els) e ('S i) where hget (HSCons _ els) = hget els -- | Enables deriving of the fact that 'e' is contained within 'els' and it's -- safe to say that 'hget' can be performed on this particular pair. type HGetable els e = HGet els e (Index e els) hask :: (MonadReader (HSet els) m, HGetable els e) => m e hask = do h <- ask return $ hget h {- | Takes subset of some hset, including subset of same elements in different order >>> let x = (HSCons "hello" $ HSCons 1234 $ HSCons 12.123 HSNil) :: HSet '[String, Int, Double] >>> subHSet x :: HSet '[Double, Int] HSCons (12.123) (HSCons (1234) (HSNil)) >>> subHSet x :: HSet '[String, Double] HSCons ("hello") (HSCons (12.123) (HSNil)) >>> subHSet x :: HSet '[Int, String] HSCons (1234) (HSCons ("hello") (HSNil)) -} class (eq ~ TEq els els2) => SubHSet els els2 eq where subHSet :: HSet els -> HSet els2 instance (eq ~ TEq els '[]) => SubHSet els '[] eq where subHSet _ = HSNil instance ( HGetable els el, 'False ~ Elem el els2 , SubHSet els els2 subeq , 'False ~ TEq els (el ': els2) ) => SubHSet els (el ': els2) 'False where subHSet h = HSCons (hget h :: el) (subHSet h :: HSet els2) instance ( HGetable els el, 'False ~ Elem el els2 , SubHSet els els2 subeq , els ~ (el ': els2) , 'True ~ TEq els (el ': els2) ) => SubHSet els (el ': els2) 'True where subHSet h = h type SubHSetable els1 els2 eq = (SubHSet els1 els2 eq, eq ~ TEq els1 els2 ) {- | Removes element from HSet of specified type >>> let x = (HSCons "sdf" $ HSCons 123 HSNil) :: HSet '[String, Int] >>> hdelete (Proxy :: Proxy Int) x HSCons ("sdf") (HSNil) >>> hdelete (Proxy :: Proxy String) x HSCons (123) (HSNil) -} hdelete :: (SubHSetable els (Delete a els) eq) => proxy a -> HSet els -> HSet (Delete a els) hdelete _ = subHSet {- | Like 'subHSet' but with proxy for convenience >>> let x = (HSCons "hello" $ HSCons 123 $ HSCons 345 HSNil) :: HSet '[String, Int, Integer] >>> hnarrow (Proxy :: Proxy '[]) x HSNil >>> hnarrow (Proxy :: Proxy '[String]) x HSCons ("hello") (HSNil) >>> hnarrow (Proxy :: Proxy '[Int, Integer]) x HSCons (123) (HSCons (345) (HSNil)) >>> hnarrow (Proxy :: Proxy '[Integer, Int]) x HSCons (345) (HSCons (123) (HSNil)) -} hnarrow :: (SubHSetable els subels eq) => proxy subels -> HSet els -> HSet subels hnarrow _ = subHSet {- | >>> let y = HSCons (Labeled 10 :: Labeled "x" Int) $ HSCons (Labeled 20 :: Labeled "y" Int) HSNil >>> y HSCons (Labeled {unLabeled = 10}) (HSCons (Labeled {unLabeled = 20}) (HSNil)) >>> hgetLabeled (Proxy :: Proxy "x") y :: Int 10 >>> hgetLabeled (Proxy :: Proxy "y") y :: Int 20 -} hgetLabeled :: forall proxy label e els. (HGetable els (Labeled label e)) => proxy label -> HSet els -> e hgetLabeled _ hset = let x = hget hset in unLabeled (x :: Labeled label e) haskLabeled :: forall proxy label e els m. #if MIN_VERSION_base(4, 8, 0) (HGetable els (Labeled label e), MonadReader (HSet els) m) #else (HGetable els (Labeled label e), MonadReader (HSet els) m, Applicative m) #endif => proxy label -> m e haskLabeled p = hgetLabeled p <$> ask