{-# LANGUAGE DataKinds #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeInType #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -Wall #-} {-# OPTIONS_GHC -Werror=incomplete-patterns #-} {-| Module : Fcf.Data.Set Description : Set data-structure for type-level programming Copyright : (c) gspia 2020- License : BSD Maintainer : gspia = Fcf.Data.Set Set provides an interface which is similar to the that given by the containers-package. If a method is missing here that you need, please do open up an issue or better, make a PR. Many of the examples are from containers-package. The internal representation is based on lists. We hope that a more efficient one will be used one day. -} -------------------------------------------------------------------------------- module Fcf.Data.Set ( Set (..) -- * Query , Member , NotMember , Null , Size , IsSubsetOf , IsProperSubsetOf -- * Construction , Empty , Singleton , Insert , Delete , PowerSet -- * Combine , Union , Difference , Intersection -- * List , FromList , ToList ) where -------------------------------------------------------------------------------- import qualified GHC.TypeLits as TL import Fcf ( Eval, Exp, type (=<<), type (<=<), type (&&) , Not, If, Map, Flip, TyEq ) import qualified Fcf as Fcf (Foldr, Filter) import Fcf.Data.List ( Elem, Cons, Concat, Reverse, Length, type (++) , ZipWith, Replicate) import Fcf.Alg.List ( All, Any ) -------------------------------------------------------------------------------- import Fcf.Alg.List ( ListF(..), ListToFix) import Fcf.Alg.Morphism -------------------------------------------------------------------------------- -- For the doctests: -- $setup -- >>> import qualified GHC.TypeLits as TL -- >>> import Fcf.Data.Nat -- >>> import Fcf.Data.Symbol -- >>> import Fcf.Alg.Sort -------------------------------------------------------------------------------- -- | Set-definition. data Set a = Set [a] -------------------------------------------------------------------------------- -- | Empty -- -- === __Example__ -- -- >>> :kind! (Eval Empty :: Set Nat) -- (Eval Empty :: Set Nat) :: Set Nat -- = 'Set '[] -- -- See also the other examples in this module. data Empty :: Exp (Set v) type instance Eval Empty = 'Set '[] -- | Singleton -- -- === __Example__ -- -- >>> :kind! Eval (Singleton 1) -- Eval (Singleton 1) :: Set Nat -- = 'Set '[1] data Singleton :: v -> Exp (Set v) type instance Eval (Singleton v) = 'Set '[v] -- | Insert -- -- === __Example__ -- -- >>> :kind! Eval (Insert 3 =<< FromList '[1, 2]) -- Eval (Insert 3 =<< FromList '[1, 2]) :: Set Nat -- = 'Set '[3, 1, 2] -- -- >>> :kind! Eval (Insert 2 =<< FromList '[1, 2]) -- Eval (Insert 2 =<< FromList '[1, 2]) :: Set Nat -- = 'Set '[1, 2] data Insert :: v -> Set v -> Exp (Set v) type instance Eval (Insert v ('Set lst)) = If (Eval (Elem v lst)) ('Set lst) ('Set (v ': lst)) -- | Delete -- -- === __Example__ -- -- >>> :kind! Eval (Delete 5 =<< FromList '[5, 3]) -- Eval (Delete 5 =<< FromList '[5, 3]) :: Set Nat -- = 'Set '[3] -- -- >>> :kind! Eval (Delete 7 =<< FromList '[5, 3]) -- Eval (Delete 7 =<< FromList '[5, 3]) :: Set Nat -- = 'Set '[5, 3] data Delete :: v -> Set v -> Exp (Set v) type instance Eval (Delete v ('Set lst)) = 'Set (Eval (Fcf.Filter (Not <=< TyEq v) lst)) -- | Member -- -- === __Example__ -- -- >>> :kind! Eval (Member 5 =<< FromList '[5, 3]) -- Eval (Member 5 =<< FromList '[5, 3]) :: Bool -- = 'True -- >>> :kind! Eval (Member 7 =<< FromList '[5, 3]) -- Eval (Member 7 =<< FromList '[5, 3]) :: Bool -- = 'False data Member :: v -> Set v -> Exp Bool type instance Eval (Member v ('Set lst)) = Eval (Elem v lst) -- | NotMember -- -- === __Example__ -- -- >>> :kind! Eval (NotMember 5 =<< FromList '[5, 3]) -- Eval (NotMember 5 =<< FromList '[5, 3]) :: Bool -- = 'False -- >>> :kind! Eval (NotMember 7 =<< FromList '[5, 3]) -- Eval (NotMember 7 =<< FromList '[5, 3]) :: Bool -- = 'True data NotMember :: v -> Set v -> Exp Bool type instance Eval (NotMember k ('Set lst)) = Eval (Not =<< Elem k lst) -- | Null -- -- === __Example__ -- -- >>> :kind! Eval (Null =<< FromList '[5, 3]) -- Eval (Null =<< FromList '[5, 3]) :: Bool -- = 'False -- >>> :kind! Eval (Null =<< Empty) -- Eval (Null =<< Empty) :: Bool -- = 'True data Null :: Set v -> Exp Bool type instance Eval (Null ('Set '[])) = 'True type instance Eval (Null ('Set (_ ': _))) = 'False -- | Size -- -- === __Example__ -- -- >>> :kind! Eval (Size =<< FromList '[5, 3]) -- Eval (Size =<< FromList '[5, 3]) :: Nat -- = 2 data Size :: Set v -> Exp TL.Nat type instance Eval (Size ('Set lst)) = Eval (Length lst) -- | IsSubsetOf -- -- === __Example__ -- -- >>> :kind! Eval (IsSubsetOf ('Set '[]) ('Set '[0,1,2,3,4])) -- Eval (IsSubsetOf ('Set '[]) ('Set '[0,1,2,3,4])) :: Bool -- = 'True -- -- >>> :kind! Eval (IsSubsetOf ('Set '[0,1]) ('Set '[0,1,2,3,4])) -- Eval (IsSubsetOf ('Set '[0,1]) ('Set '[0,1,2,3,4])) :: Bool -- = 'True -- -- >>> :kind! Eval (IsSubsetOf ('Set '[0,2,1,3,4]) ('Set '[0,1,2,3,4])) -- Eval (IsSubsetOf ('Set '[0,2,1,3,4]) ('Set '[0,1,2,3,4])) :: Bool -- = 'True -- -- >>> :kind! Eval (IsSubsetOf ('Set '[0,1,2,3,4,5]) ('Set '[0,1,2,3,4])) -- Eval (IsSubsetOf ('Set '[0,1,2,3,4,5]) ('Set '[0,1,2,3,4])) :: Bool -- = 'False data IsSubsetOf :: Set a -> Set a -> Exp Bool type instance Eval (IsSubsetOf ('Set s1) ('Set s2)) = Eval (All (Flip Elem s2) s1) -- | IsProperSubsetOf -- -- === __Example__ -- -- >>> :kind! Eval (IsProperSubsetOf ('Set '[0,1,2,3,4]) ('Set '[0,1,2,3,4])) -- Eval (IsProperSubsetOf ('Set '[0,1,2,3,4]) ('Set '[0,1,2,3,4])) :: Bool -- = 'False -- -- >>> :kind! Eval (IsProperSubsetOf ('Set '[0,2,1,3]) ('Set '[0,1,2,3,4])) -- Eval (IsProperSubsetOf ('Set '[0,2,1,3]) ('Set '[0,1,2,3,4])) :: Bool -- = 'True data IsProperSubsetOf :: Set a -> Set a -> Exp Bool type instance Eval (IsProperSubsetOf ('Set s1) ('Set s2)) = Eval (Eval (All (Flip Elem s2) s1) && Eval (Any (Not <=< Flip Elem s1) s2)) -- | Type-level set union. -- -- === __Example__ -- -- >>> :kind! Eval (Union (Eval (FromList '[5, 3])) (Eval (FromList '[5, 7])) ) -- Eval (Union (Eval (FromList '[5, 3])) (Eval (FromList '[5, 7])) ) :: Set -- Nat -- = 'Set '[7, 5, 3] data Union :: Set v -> Set v -> Exp (Set v) type instance Eval (Union ('Set lst1) ('Set lst2)) = 'Set (Eval (Fcf.Foldr UComb lst1 lst2)) data UComb :: v -> [v] -> Exp [v] type instance Eval (UComb v lst) = If (Eval (Elem v lst)) lst (v ': lst) -- | Type-level set difference. -- -- === __Example__ -- -- >>> :kind! Eval (Difference (Eval (FromList '[3, 5])) (Eval (FromList '[5, 7]))) -- Eval (Difference (Eval (FromList '[3, 5])) (Eval (FromList '[5, 7]))) :: Set -- Nat -- = 'Set '[3] data Difference :: Set v -> Set v -> Exp (Set v) type instance Eval (Difference ('Set lst1) ('Set lst2)) = 'Set (Eval (Fcf.Filter (DiffNotMem lst2) lst1)) -- helper data DiffNotMem :: [v] -> v -> Exp Bool type instance Eval (DiffNotMem lst v) = Eval (Not =<< Elem v lst) -- | Type-level set intersection. -- -- === __Example__ -- -- >>> :kind! Eval (Intersection (Eval (FromList '[3, 5])) (Eval (FromList '[5, 7]))) -- Eval (Intersection (Eval (FromList '[3, 5])) (Eval (FromList '[5, 7]))) :: Set -- Nat -- = 'Set '[5] data Intersection :: Set v -> Set v -> Exp (Set v) type instance Eval (Intersection ('Set lst1) ('Set lst2)) = 'Set (Eval (Fcf.Filter (InterMem lst2) lst1)) -- helper data InterMem :: [v ]-> v -> Exp Bool type instance Eval (InterMem lst v) = Eval (Elem v lst) -------------------------------------------------------------------------------- -- helper for PowerSet data AddFalses :: [[Bool]] -> Exp [[Bool]] type instance Eval (AddFalses lst) = Eval (Map (Cons 'False) lst) -- helper for PowerSet data AddTrues :: [[Bool]] -> Exp [[Bool]] type instance Eval (AddTrues lst) = Eval (Map (Cons 'True) lst) -- helper for PowerSet data ExtendBitList :: [[Bool]] -> Exp [[Bool]] type instance Eval (ExtendBitList lst) = Eval ((Eval (AddFalses lst)) ++ (Eval (AddTrues =<< Map Reverse lst))) -- helper for PowerSet -- :kind! Eval (Cata BuildGrayBitListsAlg=<< ListToFix =<< Replicate 3 '[]) data BuildGrayBitListsAlg :: Algebra (ListF [[Bool]]) [[Bool]] type instance Eval (BuildGrayBitListsAlg 'NilF) = '[ '[] ] type instance Eval (BuildGrayBitListsAlg ('ConsF _ lst)) = Eval (ExtendBitList lst) -- helper for PowerSet -- :kind! Eval (BuildGrayBitLists '[1,2,3,4]) data BuildGrayBitLists :: [a] -> Exp [[Bool]] type instance Eval (BuildGrayBitLists lst) = Eval (Cata BuildGrayBitListsAlg =<< ListToFix =<< Replicate (Eval (Length lst)) '[]) -- helper for PowerSet data SelWithBool :: a -> Bool -> Exp [a] type instance Eval (SelWithBool a b) = If b '[a] '[] -- helper for PowerSet data SelectWithBools :: [a] -> [Bool] -> Exp [a] type instance Eval (SelectWithBools elms bls) = Eval (Concat =<< ZipWith SelWithBool elms bls) -- | Calculate the power sets of a given type-level list. The algorithm is based -- on Gray codes. -- -- === __Example__ -- -- >>> :kind! Eval (PowerSet =<< FromList '["a", "b", "c"]) -- Eval (PowerSet =<< FromList '["a", "b", "c"]) :: Set (Set Symbol) -- = 'Set -- '[ 'Set '[], 'Set '["c"], 'Set '["b"], 'Set '["b", "c"], -- 'Set '["a"], 'Set '["a", "b"], 'Set '["a", "c"], -- 'Set '["a", "b", "c"]] -- -- >>> :kind! Eval (PowerSet =<< FromList '[Int, Char, Maybe Int]) -- Eval (PowerSet =<< FromList '[Int, Char, Maybe Int]) :: Set (Set *) -- = 'Set -- '[ 'Set '[], 'Set '[Maybe Int], 'Set '[Char], -- 'Set '[Char, Maybe Int], 'Set '[Int], 'Set '[Int, Char], -- 'Set '[Int, Maybe Int], 'Set '[Int, Char, Maybe Int]] -- data PowerSet :: Set a -> Exp (Set (Set a)) type instance Eval (PowerSet ('Set lst)) = 'Set (Eval (Map FromList =<< Map (SelectWithBools lst) =<< BuildGrayBitLists lst)) -------------------------------------------------------------------------------- -- | Use FromList to construct a Set from type-level list. -- -- === __Example__ -- -- >>> :kind! Eval (FromList '[1, 2]) -- Eval (FromList '[1, 2]) :: Set Nat -- = 'Set '[1, 2] data FromList :: [v] -> Exp (Set v) type instance Eval (FromList lst) = 'Set lst -- | Get the type-level list out of the 'Set'. -- -- === __Example__ -- -- >>> :kind! Eval (ToList =<< PowerSet =<< FromList '[1,2,3]) -- Eval (ToList =<< PowerSet =<< FromList '[1,2,3]) :: [Set Nat] -- = '[ 'Set '[], 'Set '[3], 'Set '[2], 'Set '[2, 3], 'Set '[1], -- 'Set '[1, 2], 'Set '[1, 3], 'Set '[1, 2, 3]] -- -- >>> :kind! Eval (Qsort NatListOrd =<< Map ToList =<< ToList =<< PowerSet =<< FromList '[1,2,3]) -- Eval (Qsort NatListOrd =<< Map ToList =<< ToList =<< PowerSet =<< FromList '[1,2,3]) :: [[Nat]] -- = '[ '[], '[1], '[1, 2], '[1, 2, 3], '[1, 3], '[2], '[2, 3], '[3]] data ToList :: Set v -> Exp [v] type instance Eval (ToList ('Set lst)) = lst