ixset-typed 0.1.0.0 → 0.1.1
raw patch · 2 files changed
+68/−48 lines, 2 filesdep ~basedep ~template-haskell
Dependency ranges changed: base, template-haskell
Files
- ixset-typed.cabal +5/−5
- src/Data/IxSet/Typed.hs +63/−43
ixset-typed.cabal view
@@ -1,13 +1,13 @@ name: ixset-typed-version: 0.1.0.0+version: 0.1.1 synopsis: Efficient relational queries on Haskell sets. description: Create and query sets that are indexed by multiple indices.-+ . This is a variant of the ixset package that tracks the index information via the type system. It should be safer to use than ixset, but also requires more GHC extensions.-+ . The two packages are currently relatively compatible. Switching from one to the other requires a little bit of manual work, but not very much.@@ -23,11 +23,11 @@ location: https://github.com/kosmikus/ixset-typed.git library- build-depends: base >= 4 && < 5,+ build-depends: base >= 4.6 && < 5, syb >= 0.4 && < 1, containers >= 0.5 && < 1, safecopy >= 0.8 && < 1,- template-haskell >= 2.4+ template-haskell >= 2.8 && < 3 hs-source-dirs: src exposed-modules:
src/Data/IxSet/Typed.hs view
@@ -94,7 +94,7 @@ > getFirstAuthor (Entry author _ _ _ _) = [FirstAuthor author] > > type EntryIxs = '[..., FirstAuthor]-> instance Indexable Entry where+> instance Indexable EntryIxs Entry where > empty = mkEmpty > ... > (ixFun getFirstAuthor)@@ -108,6 +108,7 @@ -- * Set type IxSet, Indexable(..),+ All, noCalcs, inferIxSet, ixSet,@@ -117,6 +118,7 @@ -- * Changes to set IndexOp,+ SetOp, change, insert, insertList,@@ -199,7 +201,10 @@ -- the core datatypes --- | Set with associated indexes.+-- | Set with associated indices.+--+-- The type-level list 'ixs' contains all types that are valid index keys.+-- The type 'a' is the type of elements in the indexed set. data IxSet (ixs :: [*]) (a :: *) where IxSet :: Set a -> IxList ixs a -> IxSet ixs a @@ -212,6 +217,17 @@ infixr 5 ::: +-- | The constraint @All c xs@ says the @c@ has to hold for all+-- elements in the type-level list @xs@.+--+-- Example:+--+-- > All Ord '[Int, Char, Bool]+--+-- is equivalent to+--+-- > (Ord Int, Ord Char, Ord Bool)+-- type family All (c :: * -> Constraint) (xs :: [*]) :: Constraint type instance All c '[] = () type instance All c (x ': xs) = (c x, All c xs)@@ -256,20 +272,25 @@ access (_x ::: xs) = access xs mapAt fh ft (x ::: xs) = ft x ::: mapAt fh ft xs --- | Create an 'IxSet' using a list of indexes. Useful in the 'Indexable'--- 'empty' method. Use 'ixFun' and 'ixGen' as list elements.+-- | Create an 'IxSet' using a set and a number of indexes. If you want to+-- use this in the 'Indexable' 'empty' method, better use 'mkEmpty' instead. ----- > instance Indexable Type where--- > empty = ixSet [ ...--- > ixFun getIndex1--- > ixGen (Proxy :: Proxy Index2Type)--- > ]+-- Note that this function takes a variable number of arguments. ----- Every value in the 'IxSet' must be reachable by the first index in this--- list, or you'll get a runtime error. ixSet :: MkIxSet ixs ixs a r => Set a -> r ixSet s = ixSet' (IxSet s) +-- | Create an empty 'IxSet' using a number of indexes. Useful in the 'Indexable'+-- 'empty' method. Use 'ixFun' and 'ixGen' for the individual indexes.+--+-- Note that this function takes a variable number of arguments.+--+-- > instance Indexable '[..., Index1Type, Index2Type] Type where+-- > empty = mkEmpty+-- > ...+-- > (ixFun getIndex1)+-- > (ixGen (Proxy :: Proxy Index2Type))+-- mkEmpty :: MkIxSet ixs ixs a r => r mkEmpty = ixSet Set.empty @@ -285,12 +306,14 @@ -- | Create a functional index. Provided function should return a list -- of indexes where the value should be found. --+-- > getIndexes :: Type -> [IndexType] -- > getIndexes value = [...indexes...] ----- > instance Indexable Type where--- > empty = ixSet [ ixFun getIndexes ]+-- > instance Indexable '[IndexType] Type where+-- > empty = mkEmpty (ixFun getIndexes) -- -- This is the recommended way to create indexes.+-- ixFun :: Ord ix => (a -> [ix]) -> Ix ix a ixFun = Ix Map.empty @@ -304,6 +327,7 @@ -- -- In production systems consider using 'ixFun' in place of 'ixGen' as -- the former one is much faster.+-- ixGen :: forall proxy a ix. (Ord ix, Data a, Typeable ix) => proxy ix -> Ix ix a ixGen _proxy = ixFun (flatten :: a -> [ix]) @@ -374,30 +398,26 @@ noCalcs :: t -> () noCalcs _ = () -{- | Template Haskell helper function for automatically building an-'Indexable' instance from a data type, e.g.--> data Foo = Foo Int String--and--> $(inferIxSet "FooDB" ''Foo 'noCalcs [''Int,''String])--will build a type synonym--> type FooDB = IxSet Foo--with @Int@ and @String@ as indexes.--/WARNING/: The type specified as the first index must be a type which-appears in all values in the 'IxSet' or 'toList', 'toSet' and-serialization will not function properly. You will be warned not to do-this with a runtime error. You can always use the element type-itself. For example:--> $(inferIxSet "FooDB" ''Foo 'noCalcs [''Foo, ''Int, ''String])---}+-- | Template Haskell helper function for automatically building an+-- 'Indexable' instance from a data type, e.g.+--+-- > data Foo = Foo Int String+--+-- and+--+-- > $(inferIxSet "FooDB" ''Foo 'noCalcs [''Int,''String])+--+-- will build a type synonym+--+-- > type FooDB = IxSet '[Int, String] Foo+--+-- with @Int@ and @String@ as indexes.+--+-- /WARNING/: This function uses 'flattenWithCalcs' for index generation,+-- which in turn uses an SYB type-based traversal. It is often more efficient+-- (and sometimes more correct) to explicitly define the indices using+-- 'ixFun'.+-- inferIxSet :: String -> TH.Name -> TH.Name -> [TH.Name] -> Q [Dec] inferIxSet _ _ _ [] = error "inferIxSet needs at least one index" inferIxSet ixset typeName calName entryPoints@@ -566,18 +586,18 @@ delete :: Indexable ixs a => a -> IxSet ixs a -> IxSet ixs a delete = change Set.delete Ix.delete --- | Will replace the item with index k. Only works if there is at--- most one item with that index in the 'IxSet'. Will not change--- 'IxSet' if you have more then 1 item with given index.+-- | Will replace the item with the given index of type 'ix'.+-- Only works if there is at most one item with that index in the 'IxSet'.+-- Will not change 'IxSet' if you have more than one item with given index. updateIx :: (Indexable ixs a, IsIndexOf ix ixs, Ord ix) => ix -> a -> IxSet ixs a -> IxSet ixs a updateIx i new ixset = insert new $ maybe ixset (flip delete ixset) $ getOne $ ixset @= i --- | Will delete the item with index k. Only works if there is at--- most one item with that index in the 'IxSet'. Will not change--- 'IxSet' if you have more then 1 item with given index.+-- | Will delete the item with the given index of type 'ix'.+-- Only works if there is at most one item with that index in the 'IxSet'.+-- Will not change 'IxSet' if you have more than one item with given index. deleteIx :: (Indexable ixs a, IsIndexOf ix ixs, Ord ix) => ix -> IxSet ixs a -> IxSet ixs a deleteIx i ixset = maybe ixset (flip delete ixset) $