WeakSets 0.4.0.0 → 1.0.0.0
raw patch · 16 files changed
+1712/−610 lines, 16 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Data.WeakSets.HomogeneousFunction: (|!|) :: Eq k => Function k v -> k -> v
- Data.WeakSets.HomogeneousFunction: (|.|) :: (Eq a, Eq b) => Function b c -> Function a b -> Function a c
- Data.WeakSets.HomogeneousFunction: (|?|) :: Eq k => Function k v -> k -> Maybe v
- Data.WeakSets.HomogeneousFunction: adjust :: Eq k => (a -> a) -> k -> Function k a -> Function k a
- Data.WeakSets.HomogeneousFunction: adjustWithKey :: Eq k => (k -> a -> a) -> k -> Function k a -> Function k a
- Data.WeakSets.HomogeneousFunction: alter :: Eq k => (Maybe a -> Maybe a) -> k -> Function k a -> Function k a
- Data.WeakSets.HomogeneousFunction: data Function k v
- Data.WeakSets.HomogeneousFunction: delete :: Eq k => k -> Function k a -> Function k a
- Data.WeakSets.HomogeneousFunction: domain :: Function k v -> Set k
- Data.WeakSets.HomogeneousFunction: elems :: Function k v -> Set v
- Data.WeakSets.HomogeneousFunction: findWithDefault :: Eq k => Function k v -> v -> k -> v
- Data.WeakSets.HomogeneousFunction: function :: AssociationList k v -> Function k v
- Data.WeakSets.HomogeneousFunction: functionToSet :: Eq k => Function k v -> Set (k, v)
- Data.WeakSets.HomogeneousFunction: idFromSet :: Set a -> Function a a
- Data.WeakSets.HomogeneousFunction: image :: Function k v -> Set v
- Data.WeakSets.HomogeneousFunction: insert :: k -> v -> Function k v -> Function k v
- Data.WeakSets.HomogeneousFunction: insertWith :: Eq k => (v -> v -> v) -> k -> v -> Function k v -> Function k v
- Data.WeakSets.HomogeneousFunction: insertWithKey :: Eq k => (k -> a -> a -> a) -> k -> a -> Function k a -> Function k a
- Data.WeakSets.HomogeneousFunction: instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Data.WeakSets.HomogeneousFunction.Function k v)
- Data.WeakSets.HomogeneousFunction: instance (GHC.Show.Show k, GHC.Show.Show v) => GHC.Show.Show (Data.WeakSets.HomogeneousFunction.Function k v)
- Data.WeakSets.HomogeneousFunction: instance Data.Foldable.Foldable (Data.WeakSets.HomogeneousFunction.Function k)
- Data.WeakSets.HomogeneousFunction: instance GHC.Base.Functor (Data.WeakSets.HomogeneousFunction.Function k)
- Data.WeakSets.HomogeneousFunction: instance GHC.Base.Monoid (Data.WeakSets.HomogeneousFunction.Function k v)
- Data.WeakSets.HomogeneousFunction: instance GHC.Base.Semigroup (Data.WeakSets.HomogeneousFunction.Function k v)
- Data.WeakSets.HomogeneousFunction: keys :: Function k v -> Set k
- Data.WeakSets.HomogeneousFunction: mapKeys :: (k1 -> k2) -> Function k1 v -> Function k2 v
- Data.WeakSets.HomogeneousFunction: member :: Eq k => Function k v -> k -> Bool
- Data.WeakSets.HomogeneousFunction: memorizeFunction :: (k -> v) -> Set k -> Function k v
- Data.WeakSets.HomogeneousFunction: notMember :: Eq k => Function k v -> k -> Bool
- Data.WeakSets.HomogeneousFunction: size :: Eq k => Function k v -> Int
- Data.WeakSets.HomogeneousFunction: type AssociationList k v = [(k, v)]
- Data.WeakSets.HomogeneousFunction: union :: Eq k => Function k a -> Function k a -> Function k a
- Data.WeakSets.HomogeneousSet: (|&|) :: Eq a => Set a -> Set a -> Set a
- Data.WeakSets.HomogeneousSet: (|*|) :: Set a -> Set b -> Set (a, b)
- Data.WeakSets.HomogeneousSet: (|+|) :: Set a -> Set b -> Set (Either a b)
- Data.WeakSets.HomogeneousSet: (|-|) :: Eq a => Set a -> Set a -> Set a
- Data.WeakSets.HomogeneousSet: (|^|) :: (Num a, Eq a) => Set a -> a -> Set [a]
- Data.WeakSets.HomogeneousSet: (|||) :: Set a -> Set a -> Set a
- Data.WeakSets.HomogeneousSet: cardinal :: Eq a => Set a -> Int
- Data.WeakSets.HomogeneousSet: catMaybesToSet :: Set (Maybe a) -> Set a
- Data.WeakSets.HomogeneousSet: data Set a
- Data.WeakSets.HomogeneousSet: filterSet :: (a -> Bool) -> Set a -> Set a
- Data.WeakSets.HomogeneousSet: instance Data.Foldable.Foldable Data.WeakSets.HomogeneousSet.Set
- Data.WeakSets.HomogeneousSet: instance GHC.Base.Applicative Data.WeakSets.HomogeneousSet.Set
- Data.WeakSets.HomogeneousSet: instance GHC.Base.Functor Data.WeakSets.HomogeneousSet.Set
- Data.WeakSets.HomogeneousSet: instance GHC.Base.Monad Data.WeakSets.HomogeneousSet.Set
- Data.WeakSets.HomogeneousSet: instance GHC.Base.Monoid (Data.WeakSets.HomogeneousSet.Set a)
- Data.WeakSets.HomogeneousSet: instance GHC.Base.Semigroup (Data.WeakSets.HomogeneousSet.Set a)
- Data.WeakSets.HomogeneousSet: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.WeakSets.HomogeneousSet.Set a)
- Data.WeakSets.HomogeneousSet: instance GHC.Show.Show a => GHC.Show.Show (Data.WeakSets.HomogeneousSet.Set a)
- Data.WeakSets.HomogeneousSet: isIn :: Eq a => a -> Set a -> Bool
- Data.WeakSets.HomogeneousSet: isIncludedIn :: Eq a => Set a -> Set a -> Bool
- Data.WeakSets.HomogeneousSet: mapMaybeToSet :: (a -> Maybe b) -> Set a -> Set b
- Data.WeakSets.HomogeneousSet: maybeToSet :: Maybe a -> Set a
- Data.WeakSets.HomogeneousSet: nubSetBy :: (a -> a -> Bool) -> Set a -> Set a
- Data.WeakSets.HomogeneousSet: powerSet :: Set a -> Set (Set a)
- Data.WeakSets.HomogeneousSet: set :: [a] -> Set a
- Data.WeakSets.HomogeneousSet: setToList :: Eq a => Set a -> [a]
- Data.WeakSets.HomogeneousSet: setToMaybe :: Set a -> Maybe a
- Math.WeakSets.PureSet: (&&&&) :: PureSet -> PureSet -> PureSet
- Math.WeakSets.PureSet: (||||) :: PureSet -> PureSet -> PureSet
- Math.WeakSets.PureSet: PureSet :: Set PureSet -> PureSet
- Math.WeakSets.PureSet: card :: PureSet -> Int
- Math.WeakSets.PureSet: cartesianProduct :: PureSet -> PureSet -> PureSet
- Math.WeakSets.PureSet: data PureSet
- Math.WeakSets.PureSet: emptySet :: PureSet
- Math.WeakSets.PureSet: formatPureSet :: PureSet -> String
- Math.WeakSets.PureSet: instance GHC.Classes.Eq Math.WeakSets.PureSet.PureSet
- Math.WeakSets.PureSet: instance GHC.Show.Show Math.WeakSets.PureSet.PureSet
- Math.WeakSets.PureSet: isInP :: PureSet -> PureSet -> Bool
- Math.WeakSets.PureSet: isIncludedInP :: PureSet -> PureSet -> Bool
- Math.WeakSets.PureSet: numberToSet :: (Num a, Eq a) => a -> PureSet
- Math.WeakSets.PureSet: pair :: PureSet -> PureSet -> PureSet
- Math.WeakSets.PureSet: powerSetP :: PureSet -> PureSet
- Math.WeakSets.PureSet: prettify :: PureSet -> String
- Math.WeakSets.PureSet: pureSet :: [PureSet] -> PureSet
- Math.WeakSets.PureSet: singleton :: PureSet -> PureSet
+ Data.WeakMap: (!) :: Eq k => Map k a -> k -> a
+ Data.WeakMap: (!?) :: Eq k => Map k a -> k -> Maybe a
+ Data.WeakMap: (\\) :: Eq k => Map k a -> Map k b -> Map k a
+ Data.WeakMap: (|!|) :: Eq k => Map k v -> k -> v
+ Data.WeakMap: (|.|) :: Eq b => Map b c -> Map a b -> Map a c
+ Data.WeakMap: (|?|) :: Eq k => Map k v -> k -> Maybe v
+ Data.WeakMap: adjust :: Eq k => (a -> a) -> k -> Map k a -> Map k a
+ Data.WeakMap: adjustWithKey :: Eq k => (k -> a -> a) -> k -> Map k a -> Map k a
+ Data.WeakMap: alter :: Eq k => (Maybe a -> Maybe a) -> k -> Map k a -> Map k a
+ Data.WeakMap: alterF :: (Functor f, Eq k) => (Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
+ Data.WeakMap: assocs :: Eq k => Map k a -> [(k, a)]
+ Data.WeakMap: compose :: Eq b => Map b c -> Map a b -> Map a c
+ Data.WeakMap: data Map k v
+ Data.WeakMap: delete :: Eq k => k -> Map k a -> Map k a
+ Data.WeakMap: deleteAt :: Eq k => Int -> Map k a -> Map k a
+ Data.WeakMap: difference :: Eq k => Map k a -> Map k b -> Map k a
+ Data.WeakMap: differenceWith :: Eq k => (a -> b -> Maybe a) -> Map k a -> Map k b -> Map k a
+ Data.WeakMap: differenceWithKey :: Eq k => (k -> a -> b -> Maybe a) -> Map k a -> Map k b -> Map k a
+ Data.WeakMap: disjoint :: Eq k => Map k a -> Map k b -> Bool
+ Data.WeakMap: domain :: Map k a -> Set k
+ Data.WeakMap: drop :: Int -> [a] -> [a]
+ Data.WeakMap: elemAt :: Eq k => Int -> Map k a -> (k, a)
+ Data.WeakMap: elems :: Eq k => Map k a -> [a]
+ Data.WeakMap: elems' :: Eq k => Map k a -> Set a
+ Data.WeakMap: elemsSet :: Eq k => Map k a -> Set a
+ Data.WeakMap: empty :: Map k a
+ Data.WeakMap: filter :: (a -> Bool) -> Map k a -> Map k a
+ Data.WeakMap: filterWithKey :: (k -> a -> Bool) -> Map k a -> Map k a
+ Data.WeakMap: findIndex :: Eq k => k -> Map k a -> Int
+ Data.WeakMap: findWithDefault :: Eq k => a -> k -> Map k a -> a
+ Data.WeakMap: foldMapWithKey :: Monoid m => (k -> a -> m) -> Map k a -> m
+ Data.WeakMap: foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
+ Data.WeakMap: foldl' :: (b -> a -> b) -> b -> Map k a -> b
+ Data.WeakMap: foldlWithKey :: (b -> k -> a -> b) -> b -> Map k a -> b
+ Data.WeakMap: foldlWithKey' :: (b -> k -> a -> b) -> b -> Map k a -> b
+ Data.WeakMap: foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
+ Data.WeakMap: foldr' :: (a -> b -> b) -> b -> Map k a -> b
+ Data.WeakMap: foldrWithKey :: (k -> a -> b -> b) -> b -> Map k a -> b
+ Data.WeakMap: foldrWithKey' :: (k -> a -> b -> b) -> b -> Map k a -> b
+ Data.WeakMap: fromAscList :: Eq k => [(k, a)] -> Map k a
+ Data.WeakMap: fromAscListWith :: Eq k => (a -> a -> a) -> [(k, a)] -> Map k a
+ Data.WeakMap: fromAscListWithKey :: Eq k => (k -> a -> a -> a) -> [(k, a)] -> Map k a
+ Data.WeakMap: fromDescList :: Eq k => [(k, a)] -> Map k a
+ Data.WeakMap: fromDescListWith :: Eq k => (a -> a -> a) -> [(k, a)] -> Map k a
+ Data.WeakMap: fromDescListWithKey :: Eq k => (k -> a -> a -> a) -> [(k, a)] -> Map k a
+ Data.WeakMap: fromDistinctAscList :: [(k, a)] -> Map k a
+ Data.WeakMap: fromDistinctDescList :: [(k, a)] -> Map k a
+ Data.WeakMap: fromList :: AssociationList k v -> Map k v
+ Data.WeakMap: fromListWith :: Eq k => (a -> a -> a) -> [(k, a)] -> Map k a
+ Data.WeakMap: fromListWithKey :: Eq k => (k -> a -> a -> a) -> [(k, a)] -> Map k a
+ Data.WeakMap: fromSet :: (k -> a) -> Set k -> Map k a
+ Data.WeakMap: idFromSet :: Set a -> Map a a
+ Data.WeakMap: image :: Eq k => Map k a -> Set a
+ Data.WeakMap: insert :: Eq k => k -> a -> Map k a -> Map k a
+ Data.WeakMap: insertLookupWithKey :: Eq k => (k -> a -> a -> a) -> k -> a -> Map k a -> (Maybe a, Map k a)
+ Data.WeakMap: insertMaybe :: Eq k => k -> Maybe a -> Map k a -> Map k a
+ Data.WeakMap: insertWith :: Eq k => (v -> v -> v) -> k -> v -> Map k v -> Map k v
+ Data.WeakMap: insertWithKey :: Eq k => (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a
+ Data.WeakMap: instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Data.WeakMap.Map k v)
+ Data.WeakMap: instance (GHC.Show.Show k, GHC.Show.Show v) => GHC.Show.Show (Data.WeakMap.Map k v)
+ Data.WeakMap: instance Data.Foldable.Foldable (Data.WeakMap.Map k)
+ Data.WeakMap: instance GHC.Base.Functor (Data.WeakMap.Map k)
+ Data.WeakMap: instance GHC.Base.Monoid (Data.WeakMap.Map k v)
+ Data.WeakMap: instance GHC.Base.Semigroup (Data.WeakMap.Map k v)
+ Data.WeakMap: intersection :: Eq k => Map k a -> Map k b -> Map k a
+ Data.WeakMap: intersectionWith :: Eq k => (a -> b -> c) -> Map k a -> Map k b -> Map k c
+ Data.WeakMap: intersectionWithKey :: Eq k => (k -> a -> b -> c) -> Map k a -> Map k b -> Map k c
+ Data.WeakMap: isProperSubmapOf :: (Eq k, Eq a) => Map k a -> Map k a -> Bool
+ Data.WeakMap: isProperSubmapOfBy :: Eq k => (a -> b -> Bool) -> Map k a -> Map k b -> Bool
+ Data.WeakMap: isSubmapOf :: (Eq k, Eq a) => Map k a -> Map k a -> Bool
+ Data.WeakMap: isSubmapOfBy :: Eq k => (a -> b -> Bool) -> Map k a -> Map k b -> Bool
+ Data.WeakMap: keys :: Eq k => Map k v -> [k]
+ Data.WeakMap: keys' :: Map k v -> Set k
+ Data.WeakMap: keysSet :: Map k a -> Set k
+ Data.WeakMap: lookup :: Eq k => k -> Map k a -> Maybe a
+ Data.WeakMap: lookupIndex :: Eq k => k -> Map k a -> Maybe Int
+ Data.WeakMap: map :: (a -> b) -> Map k a -> Map k b
+ Data.WeakMap: mapAccum :: Eq k => (a -> b -> (a, c)) -> a -> Map k b -> (a, Map k c)
+ Data.WeakMap: mapAccumRWithKey :: Eq k => (a -> k -> b -> (a, c)) -> a -> Map k b -> (a, Map k c)
+ Data.WeakMap: mapAccumWithKey :: Eq k => (a -> k -> b -> (a, c)) -> a -> Map k b -> (a, Map k c)
+ Data.WeakMap: mapEither :: (a -> Either b c) -> Map k a -> (Map k b, Map k c)
+ Data.WeakMap: mapEitherWithKey :: (k -> a -> Either b c) -> Map k a -> (Map k b, Map k c)
+ Data.WeakMap: mapKeys :: (k1 -> k2) -> Map k1 a -> Map k2 a
+ Data.WeakMap: mapKeysMonotonic :: (k1 -> k2) -> Map k1 a -> Map k2 a
+ Data.WeakMap: mapKeysWith :: (Eq k1, Eq k2) => (a -> a -> a) -> (k1 -> k2) -> Map k1 a -> Map k2 a
+ Data.WeakMap: mapMaybe :: (a -> Maybe b) -> Map k a -> Map k b
+ Data.WeakMap: mapMaybeWithKey :: (k -> a -> Maybe b) -> Map k a -> Map k b
+ Data.WeakMap: mapToList :: Eq k => Map k v -> AssociationList k v
+ Data.WeakMap: mapToSet :: Eq k => Map k v -> Set (k, v)
+ Data.WeakMap: mapWithKey :: (k -> a -> b) -> Map k a -> Map k b
+ Data.WeakMap: member :: Eq k => k -> Map k a -> Bool
+ Data.WeakMap: memorizeFunction :: (k -> v) -> Set k -> Map k v
+ Data.WeakMap: mergeWithKey :: Eq k => (k -> a -> b -> Maybe c) -> (Map k a -> Map k c) -> (Map k b -> Map k c) -> Map k a -> Map k b -> Map k c
+ Data.WeakMap: notMember :: Eq k => k -> Map k a -> Bool
+ Data.WeakMap: null :: Foldable t => t a -> Bool
+ Data.WeakMap: partition :: (a -> Bool) -> Map k a -> (Map k a, Map k a)
+ Data.WeakMap: partitionWithKey :: (k -> a -> Bool) -> Map k a -> (Map k a, Map k a)
+ Data.WeakMap: restrictKeys :: Eq k => Map k a -> Set k -> Map k a
+ Data.WeakMap: singleton :: k -> a -> Map k a
+ Data.WeakMap: size :: Eq k => Map k a -> Int
+ Data.WeakMap: splitAt :: Int -> [a] -> ([a], [a])
+ Data.WeakMap: take :: Int -> [a] -> [a]
+ Data.WeakMap: toAscList :: Eq k => Map k a -> [(k, a)]
+ Data.WeakMap: toDescList :: Eq k => Map k a -> [(k, a)]
+ Data.WeakMap: toList :: Eq k => Map k a -> [(k, a)]
+ Data.WeakMap: traverseMaybeWithKey :: (Applicative f, Eq k) => (k -> a -> f (Maybe b)) -> Map k a -> f (Map k b)
+ Data.WeakMap: traverseWithKey :: (Applicative t, Eq k) => (k -> a -> t b) -> Map k a -> t (Map k b)
+ Data.WeakMap: type AssociationList k v = [(k, v)]
+ Data.WeakMap: union :: Eq k => Map k a -> Map k a -> Map k a
+ Data.WeakMap: unionWith :: Eq k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
+ Data.WeakMap: unionWithKey :: Eq k => (k -> a -> a -> a) -> Map k a -> Map k a -> Map k a
+ Data.WeakMap: unions :: Eq k => [Map k a] -> Map k a
+ Data.WeakMap: unionsWith :: Eq k => (a -> a -> a) -> [Map k a] -> Map k a
+ Data.WeakMap: update :: Eq k => (a -> Maybe a) -> k -> Map k a -> Map k a
+ Data.WeakMap: updateAt :: Eq k => (k -> a -> Maybe a) -> Int -> Map k a -> Map k a
+ Data.WeakMap: updateLookupWithKey :: Eq k => (k -> a -> Maybe a) -> k -> Map k a -> (Maybe a, Map k a)
+ Data.WeakMap: updateWithKey :: Eq k => (k -> a -> Maybe a) -> k -> Map k a -> Map k a
+ Data.WeakMap: values :: Eq k => Map k a -> Set a
+ Data.WeakMap: weakMap :: AssociationList k v -> Map k v
+ Data.WeakMap: withoutKeys :: Eq k => Map k a -> Set k -> Map k a
+ Data.WeakMap.Safe: (|!|) :: Eq k => Map k v -> k -> v
+ Data.WeakMap.Safe: (|.|) :: Eq b => Map b c -> Map a b -> Map a c
+ Data.WeakMap.Safe: (|?|) :: Eq k => Map k v -> k -> Maybe v
+ Data.WeakMap.Safe: domain :: Map k a -> Set k
+ Data.WeakMap.Safe: elems' :: Eq k => Map k a -> Set a
+ Data.WeakMap.Safe: idFromSet :: Set a -> Map a a
+ Data.WeakMap.Safe: image :: Eq k => Map k a -> Set a
+ Data.WeakMap.Safe: keys' :: Map k v -> Set k
+ Data.WeakMap.Safe: memorizeFunction :: (k -> v) -> Set k -> Map k v
+ Data.WeakMap.Safe: weakMap :: AssociationList k v -> Map k v
+ Data.WeakSet: (\\) :: Eq a => Set a -> Set a -> Set a
+ Data.WeakSet: (|&|) :: Eq a => Set a -> Set a -> Set a
+ Data.WeakSet: (|*|) :: Set a -> Set b -> Set (a, b)
+ Data.WeakSet: (|+|) :: Set a -> Set b -> Set (Either a b)
+ Data.WeakSet: (|-|) :: Eq a => Set a -> Set a -> Set a
+ Data.WeakSet: (|^|) :: (Num a, Eq a) => Set a -> a -> Set [a]
+ Data.WeakSet: (|||) :: Set a -> Set a -> Set a
+ Data.WeakSet: alterF :: (Eq a, Functor f) => (Bool -> f Bool) -> a -> Set a -> f (Set a)
+ Data.WeakSet: cardinal :: Eq a => Set a -> Int
+ Data.WeakSet: cartesianProduct :: Set a -> Set b -> Set (a, b)
+ Data.WeakSet: catEither :: Set (Either a b) -> (Set a, Set b)
+ Data.WeakSet: catMaybes :: Set (Maybe a) -> Set a
+ Data.WeakSet: data Set a
+ Data.WeakSet: delete :: Eq a => a -> Set a -> Set a
+ Data.WeakSet: deleteAt :: Eq a => Int -> Set a -> Set a
+ Data.WeakSet: difference :: Eq a => Set a -> Set a -> Set a
+ Data.WeakSet: disjoint :: Eq a => Set a -> Set a -> Bool
+ Data.WeakSet: disjointUnion :: Set a -> Set b -> Set (Either a b)
+ Data.WeakSet: drop :: Eq a => Int -> Set a -> Set a
+ Data.WeakSet: elemAt :: Eq a => Int -> Set a -> a
+ Data.WeakSet: empty :: Set a
+ Data.WeakSet: filter :: (a -> Bool) -> Set a -> Set a
+ Data.WeakSet: findIndex :: Eq a => a -> Set a -> Int
+ Data.WeakSet: foldl' :: (a -> b -> a) -> a -> Set b -> a
+ Data.WeakSet: foldr' :: (a -> b -> b) -> b -> Set a -> b
+ Data.WeakSet: fromAscList :: [a] -> Set a
+ Data.WeakSet: fromDescList :: [a] -> Set a
+ Data.WeakSet: fromDistinctAscList :: [a] -> Set a
+ Data.WeakSet: fromDistinctDescList :: [a] -> Set a
+ Data.WeakSet: fromList :: [a] -> Set a
+ Data.WeakSet: insert :: a -> Set a -> Set a
+ Data.WeakSet: instance Data.Foldable.Foldable Data.WeakSet.Set
+ Data.WeakSet: instance GHC.Base.Applicative Data.WeakSet.Set
+ Data.WeakSet: instance GHC.Base.Functor Data.WeakSet.Set
+ Data.WeakSet: instance GHC.Base.Monad Data.WeakSet.Set
+ Data.WeakSet: instance GHC.Base.Monoid (Data.WeakSet.Set a)
+ Data.WeakSet: instance GHC.Base.Semigroup (Data.WeakSet.Set a)
+ Data.WeakSet: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.WeakSet.Set a)
+ Data.WeakSet: instance GHC.Show.Show a => GHC.Show.Show (Data.WeakSet.Set a)
+ Data.WeakSet: intersection :: Eq a => Set a -> Set a -> Set a
+ Data.WeakSet: isIn :: Eq a => a -> Set a -> Bool
+ Data.WeakSet: isIncludedIn :: Eq a => Set a -> Set a -> Bool
+ Data.WeakSet: isProperSubsetOf :: Eq a => Set a -> Set a -> Bool
+ Data.WeakSet: isSubsetOf :: Eq a => Set a -> Set a -> Bool
+ Data.WeakSet: lookupIndex :: Eq a => a -> Set a -> Maybe Int
+ Data.WeakSet: map :: (a -> b) -> Set a -> Set b
+ Data.WeakSet: mapEither :: (a -> Either b c) -> Set a -> (Set b, Set c)
+ Data.WeakSet: mapMaybe :: (a -> Maybe b) -> Set a -> Set b
+ Data.WeakSet: mapMonotonic :: (a -> b) -> Set a -> Set b
+ Data.WeakSet: maybeToSet :: Maybe a -> Set a
+ Data.WeakSet: member :: Eq a => a -> Set a -> Bool
+ Data.WeakSet: notMember :: Eq a => a -> Set a -> Bool
+ Data.WeakSet: nubSetBy :: (a -> a -> Bool) -> Set a -> [a]
+ Data.WeakSet: partition :: (a -> Bool) -> Set a -> (Set a, Set a)
+ Data.WeakSet: powerSet :: Set a -> Set (Set a)
+ Data.WeakSet: sequenceSet :: (Applicative f, Eq (f a)) => Set (f a) -> f (Set a)
+ Data.WeakSet: set :: [a] -> Set a
+ Data.WeakSet: setToList :: Eq a => Set a -> [a]
+ Data.WeakSet: setToMaybe :: Set a -> Maybe a
+ Data.WeakSet: singleton :: a -> Set a
+ Data.WeakSet: size :: Eq a => Set a -> Int
+ Data.WeakSet: splitAt :: Eq a => Int -> Set a -> (Set a, Set a)
+ Data.WeakSet: take :: Eq a => Int -> Set a -> Set a
+ Data.WeakSet: toList :: Eq a => Set a -> [a]
+ Data.WeakSet: traverseSet :: (Applicative f, Eq a) => (a -> f b) -> Set a -> f (Set b)
+ Data.WeakSet: union :: Set a -> Set a -> Set a
+ Data.WeakSet: unions :: Foldable f => f (Set a) -> Set a
+ Data.WeakSet.Safe: (|&|) :: Eq a => Set a -> Set a -> Set a
+ Data.WeakSet.Safe: (|*|) :: Set a -> Set b -> Set (a, b)
+ Data.WeakSet.Safe: (|+|) :: Set a -> Set b -> Set (Either a b)
+ Data.WeakSet.Safe: (|-|) :: Eq a => Set a -> Set a -> Set a
+ Data.WeakSet.Safe: (|^|) :: (Num a, Eq a) => Set a -> a -> Set [a]
+ Data.WeakSet.Safe: (|||) :: Set a -> Set a -> Set a
+ Data.WeakSet.Safe: cardinal :: Eq a => Set a -> Int
+ Data.WeakSet.Safe: isIn :: Eq a => a -> Set a -> Bool
+ Data.WeakSet.Safe: isIncludedIn :: Eq a => Set a -> Set a -> Bool
+ Data.WeakSet.Safe: nubSetBy :: (a -> a -> Bool) -> Set a -> [a]
+ Data.WeakSet.Safe: set :: [a] -> Set a
+ Data.WeakSet.Safe: setToList :: Eq a => Set a -> [a]
+ Math.PureSet: (&&&&) :: PureSet -> PureSet -> PureSet
+ Math.PureSet: (||||) :: PureSet -> PureSet -> PureSet
+ Math.PureSet: PureSet :: Set PureSet -> PureSet
+ Math.PureSet: card :: PureSet -> Int
+ Math.PureSet: cartesianProduct :: PureSet -> PureSet -> PureSet
+ Math.PureSet: data PureSet
+ Math.PureSet: emptySet :: PureSet
+ Math.PureSet: formatPureSet :: PureSet -> String
+ Math.PureSet: instance GHC.Classes.Eq Math.PureSet.PureSet
+ Math.PureSet: instance GHC.Show.Show Math.PureSet.PureSet
+ Math.PureSet: isInP :: PureSet -> PureSet -> Bool
+ Math.PureSet: isIncludedInP :: PureSet -> PureSet -> Bool
+ Math.PureSet: numberToSet :: (Num a, Eq a) => a -> PureSet
+ Math.PureSet: pair :: PureSet -> PureSet -> PureSet
+ Math.PureSet: powerSetP :: PureSet -> PureSet
+ Math.PureSet: prettify :: PureSet -> String
+ Math.PureSet: pureSet :: [PureSet] -> PureSet
+ Math.PureSet: singleton :: PureSet -> PureSet
Files
- Readme.md +32/−8
- WeakSets.cabal +11/−6
- src/Data/WeakMap.hs +893/−0
- src/Data/WeakMap/Safe.hs +27/−0
- src/Data/WeakSet.hs +518/−0
- src/Data/WeakSet/Safe.hs +30/−0
- src/Data/WeakSets/HomogeneousFunction.hs +0/−235
- src/Data/WeakSets/HomogeneousSet.hs +0/−163
- src/Math/PureSet.hs +138/−0
- src/Math/WeakSets/PureSet.hs +0/−136
- test/AllTests.hs +4/−4
- test/TestHomogeneousFunction.hs +0/−30
- test/TestHomogeneousSet.hs +0/−26
- test/TestPureSet.hs +1/−2
- test/TestWeakMap.hs +32/−0
- test/TestWeakSet.hs +26/−0
Readme.md view
@@ -1,32 +1,56 @@ # WeakSets -This is a Haskell package which defines sets in a more general way than Data.Set.+This is a Haskell package which defines sets and maps in a more general way than Data.Set and Data.Map of the containers package. -Data.Set only allows to create sets of types which implements the Ord typeclass, this package introduces HomogeneousSet which does not require the typeclass Ord.+This package answers three problems : -The PureSet type allows to create nested sets easily. It may be used to study set theory for example.+* how to make sets of types which do not implement the Ord typeclass (which is required by Data.Set), this problem is solved by `Data.WeakSet`;+* how to make maps of types which do not implement the Ord typeclass, this problem is solved by `Data.WeakMap`;+* how to make arbitrarily nested sets as set theory allows. This problem is resolved thanks to `Math.PureSet`. +Data.WeakSet and Data.WeakMap are (almost) backward compatible with Data.Set and Data.Map. Therefore you can replace your imports of Data.Set to Data.WeakSet and Data.Map.Strict to Data.WeakMap safely. There a a few functions which require to add an Eq typeclass as a requirement. Some functions are not implemented as they really need the Ord typeclass, if you use them you should use Data.Set or Data.Map.+ ## General info -The homogenous sets implemented in this package require the type contained in the set to implement the typeclass Eq. It ensures there are no duplicate element in the set and that the order of elements does not matter when testing equality. It is slower than Data.Set because we do not require the Ord typeclass, if you only use types which are orderable, use Data.Set instead.+A `WeakSet` is a list where duplicates elements and the order of elements are disregarded. Its stronger counterpart is Data.Set. Most of the functions related to `WeakSet` require the Eq typeclass. -The pure set type implemented in this package is a tree like structure where the order of branches does not matter. It allows arbitrary nesting of sets which is useful to do set theoretic constructions.+A `WeakMap` is an association list where duplicates entries and the order of pairs are disregarded. Its stronger counterpart is Data.Map. Most of the functions related to `WeakMap` require the Eq typeclass. +A `PureSet` is a tree-like structure where duplicate branches and the order of branches is disregarded.+++ ## Installation `cabal install WeakSets` ## Usage -Example usage of homogenous sets :+Example usage of weak sets : ```haskell-ghci> import HomogeneousSet-ghci> data Foo = Foo Int Char deriving (Eq) -- an arbitrary type which is not required to implement >Ord typeclass+ghci> import Data.WeakSet.Safe+ghci> data Foo = Foo Int Char deriving (Eq, Show) -- an arbitrary type which is not required to implement Ord typeclass ghci> s1 = set [Foo 3 'a', Foo 2 'c', Foo 3 'a'] ghci> s2 = set [Foo 2 'c', Foo 3 'a'] ghci> s1 == s2 True+ghci> s3 = set [Foo 2 'c', Foo 3 'a']+ghci> s4 = s1 ||| s3+ghci> s4+(set [Foo 3 'a',Foo 2 'c',Foo 3 'a',Foo 2 'c',Foo 3 'a'])+ghci> cardinal s4+2+```++Example usage of weak maps :++```haskell+ghci> import Data.WeakMap.Safe+ghci> data Foo = Foo Int Char deriving (Eq) -- an arbitrary type which is not required to implement Ord typeclass+ghci> m1 = weakMap [(Foo 3 'a',1), (Foo 2 'c',5), (Foo 3 'a',3)]+ghci> m1 |!| (Foo 2 'c')+5 ``` Example usage of pure sets :
WeakSets.cabal view
@@ -14,15 +14,16 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change -version: 0.4.0.0 +version: 1.0.0.0 -- A short (one-line) description of the package. synopsis: Simple set types. Useful to create sets of arbitrary types and nested sets. -- A longer description of the package. -description: This package answers two problems : how to make sets of types which does not implement the Ord typeclass and how to make arbitrarily nested sets as set theory allows. The first problem is resolved thanks to `HomogeneousSet` which is a list where duplicates elements are not allowed and the order of elements is forgotten. The second problem is resolved thanks to `PureSet`, it is a tree structure where the order of the branches does not matter. +description: This package answers two problems : how to make sets and maps of types which do not implement the Ord typeclass and how to make arbitrarily nested sets as set theory allows. The first problem is resolved thanks to `WeakSet`s and `WeakMap`s. The second problem is resolved thanks to `PureSet`. + -- URL for the project homepage or repository. homepage: https://gitlab.utc.fr/gsabbagh/sets @@ -52,9 +53,13 @@ library -- Modules exported by the library. - exposed-modules: Data.WeakSets.HomogeneousSet, - Math.WeakSets.PureSet, - Data.WeakSets.HomogeneousFunction + exposed-modules: Data.WeakSet, + Data.WeakSet.Safe, + Data.WeakMap + Data.WeakMap.Safe, + Math.PureSet +-- Math.PureSet, +-- Data.WeakMap -- Modules included in this library but not exported. -- other-modules: @@ -87,4 +92,4 @@ -- Test dependencies. build-depends: base ^>=4.15.0.0, WeakSets - other-modules: TestHomogeneousSet, TestPureSet, TestHomogeneousFunction + other-modules: TestWeakSet, TestPureSet, TestWeakMap
+ src/Data/WeakMap.hs view
@@ -0,0 +1,893 @@+{-| Module : WeakSets +Description : A `WeakMap` is a Data.Map which does not require the keys to implement the Ord typeclass. +Copyright : Guillaume Sabbagh 2022 +License : LGPL-3.0-or-later +Maintainer : guillaumesabbagh@protonmail.com +Stability : experimental +Portability : portable + +A `WeakMap` is a Data.Map which does not require the keys to implement the Ord typeclass. It is a weak set of pairs (key,value). + +The datatype only assumes its keys are equatable, it is therefore slower to access data than the Data.Map datatype. + +We use this datatype because most of the datatypes we care about are not orderable. + +Almost all Data.WeakMap functions are implemented so that you can replace a Data.Map import such as + +> import Data.Map.Strict (Map) +> import qualified Data.Map.Strict as Map + +by a Data.WeakMap import such as + +> import Data.WeakMap (Map) +> import qualified Data.WeakMap as Map + +without breaking anything in your code. + +The only functions for which this would fail are the functions converting maps back into list (they require the Eq typeclass unlike in Data.Map). `size` is one of them. + +If a function really requires the Ord typeclass to even make sense, then it is not defined in this package, you should use Data.Map. + +Note that, just like in Data.Map, the implementation is generally left-biased. Functions that take two maps as arguments and combine them, such as union and intersection, prefer the entries in the first argument to those in the second. + +Functions with non colliding names are defined in Data.WeakMap.Safe. Inline functions are written between pipes @|@. + +This module is intended to be imported qualified, to avoid name clashes with Prelude functions, except for functions in Data.WeakSet.Map, e.g. + +> import Data.WeakMap (Map) +> import qualified Data.WeakMap as Map +> import Data.WeakMap.Safe + +Unlike Data.Map, we defer the removing of duplicate keys to the conversion back to a list. + +Beware if the map is supposed to contain a lot of duplicate keys, you should purge them yourself by transforming the map into a list and back into a map. The time complexity is always given in function of the number of pairs in the map including the duplicate pairs. +-} + +module Data.WeakMap +( + -- * Map type + AssociationList(..) + , Map + + -- * Construction + , weakMap + , empty + , singleton + , fromSet + + -- ** From Unordered Lists + , fromList + , fromListWith + , fromListWithKey + + -- ** From Ascending Lists + , fromAscList + , fromAscListWith + , fromAscListWithKey + , fromDistinctAscList + + -- ** From Descending Lists + , fromDescList + , fromDescListWith + , fromDescListWithKey + , fromDistinctDescList + + -- * Insertion + , insert + , insertWith + , insertWithKey + , insertLookupWithKey + , insertMaybe + + -- * Deletion\/Update + , delete + , adjust + , adjustWithKey + , update + , updateWithKey + , updateLookupWithKey + , alter + , alterF + + -- * Query + -- ** Lookup + , lookup + , (!?) + , (!) + , (|?|), (|!|) + , findWithDefault + , member + , notMember + + -- ** Size + , null + , size + + -- * Combine + + -- ** Union + , union + , unionWith + , unionWithKey + , unions + , unionsWith + + -- ** Difference + , difference + , (\\) + , differenceWith + , differenceWithKey + + -- ** Intersection + , intersection + , intersectionWith + , intersectionWithKey + + -- ** Disjoint + , disjoint + + -- -- ** Compose + , (|.|) + , compose + + , mergeWithKey + + -- * Traversal + -- ** Map + , map + , mapWithKey + , traverseWithKey + , traverseMaybeWithKey + , mapAccum + , mapAccumWithKey + , mapAccumRWithKey + , mapKeys + , mapKeysWith + , mapKeysMonotonic + + -- * Folds + , foldr + , foldl + , foldrWithKey + , foldlWithKey + , foldMapWithKey + + -- ** Strict folds + , foldr' + , foldl' + , foldrWithKey' + , foldlWithKey' + + -- * Conversion + , mapToList + , mapToSet + , elems + , elems' + , values + , image + , keys + , keys' + , domain + , assocs + , keysSet + , elemsSet + + -- ** Lists + , toList + + -- ** Ordered lists + , toAscList + , toDescList + + -- * Filter + , filter + , filterWithKey + , restrictKeys + , withoutKeys + , partition + , partitionWithKey + + , mapMaybe + , mapMaybeWithKey + , mapEither + , mapEitherWithKey + + -- * Submap + , isSubmapOf, isSubmapOfBy + , isProperSubmapOf, isProperSubmapOfBy + + -- * Indexed + , lookupIndex + , findIndex + , elemAt + , updateAt + , deleteAt + , take + , drop + , splitAt + + -- * Others + , idFromSet + , memorizeFunction +) where +import Prelude hiding (lookup, map, filter) +import Data.WeakSet (Set) +import qualified Data.WeakSet as Set +import Data.WeakSet.Safe +import qualified Data.List as L +import Data.Maybe (fromJust) +import Control.Applicative (liftA3) +import qualified Data.Foldable as Foldable + +-- | An association list is a list of pairs (key,value). +type AssociationList k v = [(k,v)] + +-- | A weak map is a weak set of pairs (key,value) such that their should only be one pair with a given key. +-- +-- It is an abstract type, the smart constructor is `weakMap`. +data Map k v = Map {-# UNPACK #-} !(Set (k,v)) deriving (Eq) + +instance (Show k, Show v) => Show (Map k v) where + show (Map al) = "(weakMap "++show al++")" + +instance Semigroup (Map k v) where + (Map al1) <> (Map al2) = Map $ al1 <> al2 + +instance Monoid (Map k v) where + mempty = Map (set []) + +instance Foldable (Map k) where + foldr f d (Map al) = foldr (\(k,v) -> f v) d al + +instance Functor (Map k) where + fmap f (Map al) = Map $ (\(k,v) -> (k,f v)) <$> al + + +-- Construction + +-- | /O(1)/. The smart constructor of weak maps. This is the only way of instantiating a `Map`. +-- +-- Takes an association list and returns a function which maps to each key the value associated. +-- +-- If several pairs have the same keys, they are kept until the user wants an association list back. +weakMap :: AssociationList k v -> Map k v +weakMap al = Map $ set $ al + +-- | /O(1)/. Alias of `weakMap` for backward compatibility with Data.Map. +fromList :: AssociationList k v -> Map k v +fromList = weakMap + +-- | Alias of mempty for backward compatibility with Data.Map. +empty :: Map k a +empty = mempty + +-- | /O(1)/. A map with a single pair (key,value). +singleton :: k -> a -> Map k a +singleton k v = Map $ set [(k,v)] + +-- | /O(n)/. Build a map from a set of keys and a function which for each key computes its value. +fromSet :: (k -> a) -> Set k -> Map k a +fromSet f s = Map $ (\x -> (x, f x)) <$> s + +-- | /O(n)/. Build a map from a list of key/value pairs with a combining function. +fromListWith :: (Eq k) => (a -> a -> a) -> [(k, a)] -> Map k a +fromListWith f xs = fromListWithKey (\_ x y -> f x y) xs + +-- | /O(n)/. Build a map from a list of key/value pairs with a combining function. +fromListWithKey :: (Eq k) => (k -> a -> a -> a) -> [(k, a)] -> Map k a +fromListWithKey c [] = empty +fromListWithKey c ((k,v):xs) = insertWithKey c k v (fromListWithKey c xs) + +-- | Alias for backward compatibility. +fromAscList :: Eq k => [(k, a)] -> Map k a +fromAscList = fromList + +-- | Alias for backward compatibility. +fromAscListWith :: Eq k => (a -> a -> a) -> [(k, a)] -> Map k a +fromAscListWith = fromListWith + +-- | Alias for backward compatibility. +fromAscListWithKey :: Eq k => (k -> a -> a -> a) -> [(k, a)] -> Map k a +fromAscListWithKey = fromListWithKey + +-- | Alias for backward compatibility. +fromDistinctAscList :: [(k, a)] -> Map k a +fromDistinctAscList = fromList + +-- | Alias for backward compatibility. +fromDescList :: Eq k => [(k, a)] -> Map k a +fromDescList = fromList + +-- | Alias for backward compatibility. +fromDescListWith :: Eq k => (a -> a -> a) -> [(k, a)] -> Map k a +fromDescListWith = fromListWith + +-- | Alias for backward compatibility. +fromDescListWithKey :: Eq k => (k -> a -> a -> a) -> [(k, a)] -> Map k a +fromDescListWithKey = fromListWithKey + +-- | Alias for backward compatibility. +fromDistinctDescList :: [(k, a)] -> Map k a +fromDistinctDescList = fromList + +-- Operators + + +-- | /O(n)/. Lookup the value at a key in the map. If the map is not defined on the given value returns `Nothing`, otherwise returns `Just` the image. +-- +-- This function is like `lookup` in Data.Map for function (beware: the order of the argument are reversed). +(|?|) :: (Eq k) => Map k v -> k -> Maybe v +(|?|) (Map al) key = (Set.setToMaybe).(Set.catMaybes) $ (\(k,v) -> if k == key then Just v else Nothing) <$> al + +-- | /O(n)/. Unsafe version of `(|?|)`. +-- +-- This function is like `(!)` in Data.Map, it is renamed to avoid name collisions. +(|!|) :: (Eq k) => Map k v -> k -> v +(|!|) f key + | null safeResult = error "WeakMap.|!|: element not in the map" + | otherwise = result + where + safeResult = f |?| key + Just result = safeResult + +-- | O(n). Find the value at a key. Calls `error` when the element can not be found. +-- +-- Alias of `(|!|)` for backward compatibility purposes. +(!) :: (Eq k) => Map k a -> k -> a +(!) = (|!|) + +-- | Alias for backward compatibility. +(!?) :: Eq k => Map k a -> k -> Maybe a +(!?) = (|?|) + + +-- | See `difference`. +(\\) :: (Eq k) => Map k a -> Map k b -> Map k a +(\\) = difference + +-- | /O(n*m)/. Difference of two maps. Return elements of the first map not existing in the second map. +difference :: (Eq k) => Map k a -> Map k b -> Map k a +difference (Map al) m2 = Map $ Set.filter (\(k,v) -> not $ k `isIn` (keys' m2)) al + + +-- Query + + +-- | /O(n^2)/. The number of elements in the map. +size :: (Eq k) => Map k a -> Int +size m = length $ mapToList m + +-- | /O(n)/. Is the key a member of the map? See also `notMember`. +member :: (Eq k) => k -> Map k a -> Bool +member k m = not.null $ m |?| k + +-- | /O(n)/. Negation of `member`. +notMember :: (Eq k) => k -> Map k a -> Bool +notMember k m = null $ m |?| k + +-- | /O(n)/. Just like `(|?|)` but the order of argument is reversed. For backward compatibility with Data.Map. +lookup :: (Eq k) => k -> Map k a -> Maybe a +lookup x y = (|?|) y x + +-- | /O(n)/. Apply a map to a given value, if the key is in the domain returns the image, otherwise return a default value. +-- +-- This function is like `findWithDefault` (the order of the argument are reversed though). +findWithDefault' :: (Eq k) => Map k v -> v -> k -> v +findWithDefault' f d key + | null safeResult = d + | otherwise = result + where + safeResult = f |?| key + Just result = safeResult + +-- | /O(n)/. The expression @(findWithDefault def k map)@ returns the value at key k or returns default value def when the key is not in the map. +findWithDefault :: (Eq k) => a -> k -> Map k a -> a +findWithDefault d key f = findWithDefault' f d key + + +-- Insertion + + +-- | /O(1)/. Insert a new key and value in the map. If the key is already present in the map, the associated value is replaced with the supplied value. `insert` is equivalent to @`insertWith` `const`@. +insert :: (Eq k) => k -> a -> Map k a -> Map k a +insert k v (Map al) = Map $ Set.insert (k,v) al + +-- | /O(n)/. Insert with a function, combining new value and old value. @insertWith f key value mp@ will insert the pair (key, value) into mp if key does not exist in the function. If the key does exist, the function will insert the pair (key, f new_value old_value). +insertWith :: (Eq k) => (v -> v -> v) -> k -> v -> Map k v -> Map k v +insertWith comb k v f + | null prev = insert k v f + | otherwise = insert k (comb v prev_value) f + where + prev = f |?| k + Just prev_value = prev + +-- | /O(n)/. Alias for `insertWith` for backward compatibility purposes. +insertWith' :: (Eq k) => (a -> a -> a) -> k -> a -> Map k a -> Map k a +insertWith' = insertWith + +-- | /O(n)/. Insert with a function, combining key, new value and old value. @insertWithKey f key value mp@ will insert the pair (key, value) into mp if key does not exist in the function. If the key does exist, the function will insert the pair (key,f key new_value old_value). Note that the key passed to f is the same key passed to `insertWithKey`. +insertWithKey :: (Eq k) => (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a +insertWithKey comb k v f + | null prev = insert k v f + | otherwise = insert k (comb k v prev_value) f + where + prev = f |?| k + Just prev_value = prev + +-- | /O(n)/. Alias for `insertWithKey` for backward compatibility purposes. +insertWithKey' :: (Eq k) => (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a +insertWithKey' = insertWithKey + +-- | /O(n)/. Combines insert operation with old value retrieval. The expression @(insertLookupWithKey f k x map)@ is a pair where the first element is equal to @(lookup k map)@ and the second element equal to @(insertWithKey f k x map)@. +insertLookupWithKey :: (Eq k) => (k -> a -> a -> a) -> k -> a -> Map k a -> (Maybe a, Map k a) +insertLookupWithKey f k x map = (lookup k map, insertWithKey f k x map) + +-- | /O(n)/. Alias for `insertLookupWithKey` for backward compatibility purposes. +insertLookupWithKey' :: (Eq k) => (k -> a -> a -> a) -> k -> a -> Map k a -> (Maybe a, Map k a) +insertLookupWithKey' = insertLookupWithKey + +-- | /O(1)/. Insert a new key and value if it is Just in the map. If the key is already present in the map, the associated value is replaced with the supplied value. +insertMaybe :: (Eq k) => k -> Maybe a -> Map k a -> Map k a +insertMaybe _ Nothing m = m +insertMaybe k (Just v) (Map al) = Map $ Set.insert (k,v) al + + +-- Delete/update + + +-- | /O(n)/. Delete a key and its value from the map. When the key is not a member of the map, the original map is returned. +delete :: (Eq k) => k -> Map k a -> Map k a +delete key (Map al) = Map $ Set.filter (\(k,v) -> key /= k) al + +-- | /O(n)/. Update a value at a specific key with the result of the provided function. When the key is not a member of the map, the original map is returned. +adjust :: (Eq k) => (a -> a) -> k -> Map k a -> Map k a +adjust func key (Map al) = Map $ (\(k,v) -> if key == k then (k, func v) else (k,v)) <$> al + +-- | /O(n)/. Adjust a value at a specific key. When the key is not a member of the map, the original map is returned. +adjustWithKey :: (Eq k) => (k -> a -> a) -> k -> Map k a -> Map k a +adjustWithKey func key (Map al) = Map $ (\(k,v) -> if key == k then (k, func k v) else (k,v)) <$> al + +-- | /O(n)/. The expression (`alter` f k map) alters the value x at k, or absence thereof. alter can be used to insert, delete, or update a value in a `Map`. In short : `lookup` k (`alter` f k m) = f (`lookup` k m). +alter :: (Eq k) => (Maybe a -> Maybe a) -> k -> Map k a -> Map k a +alter func key f + | null lookupKey = insert key unpackedImageNothing f + | null result = delete key f + | otherwise = insert key unpackedResult f + where + lookupKey = f |?| key + result = func lookupKey + Just unpackedResult = result + Just unpackedImageNothing = func Nothing + +-- | /O(n)/. The expression (`alterF` f k map) alters the value x at k, or absence thereof. `alterF` can be used to inspect, insert, delete, or update a value in a Map. +alterF :: (Functor f, Eq k) => (Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a) +alterF func key f + | null lookupKey = add <$> imageNothing + | otherwise = treat <$> result + where + lookupKey = f |?| key + result = func lookupKey + treat x = if null x then delete key f else insert key (fromJust x) f + imageNothing = func Nothing + add x = if null x then f else insert key (fromJust x) f + + +-- | /O(n)/. The expression @(update f k map)@ updates the value x at k (if it is in the map). If (f x) is Nothing, the element is deleted. If it is (Just y), the key k is bound to the new value y. +update :: (Eq k) => (a -> Maybe a) -> k -> Map k a -> Map k a +update f = updateWithKey (\_ x -> f x) + +-- | /O(n)/. The expression @(updateWithKey f k map)@ updates the value x at k (if it is in the map). If (f k x) is Nothing, the element is deleted. If it is (Just y), the key k is bound to the new value y. +updateWithKey :: (Eq k) => (k -> a -> Maybe a) -> k -> Map k a -> Map k a +updateWithKey f key m + | null look = m + | null res = delete key m + | otherwise = insert key r m + where + look = m |?| key + Just v = look + res = f key v + Just r = res + +-- | /O(n)/. Lookup and update. See also `updateWithKey`. The function returns changed value, if it is updated. Returns the original key value if the map entry is deleted. +updateLookupWithKey :: (Eq k) => (k -> a -> Maybe a) -> k -> Map k a -> (Maybe a, Map k a) +updateLookupWithKey f key m + | null look = (Nothing, m) + | null res = (Just v, delete key m) + | otherwise = (Just v, insert key r m) + where + look = m |?| key + Just v = look + res = f key v + Just r = res + + +-- Combine + + +-- | /O(n)/. The expression @(`union` t1 t2)@ takes the left-biased union of t1 and t2. It prefers t1 when duplicate keys are encountered. +union :: (Eq k) => Map k a -> Map k a -> Map k a +union (Map al1) (Map al2) = Map $ al1 ||| al2 + +-- | /O(n)/. Union with a combining function. +unionWith :: (Eq k) => (a -> a -> a) -> Map k a -> Map k a -> Map k a +unionWith f m1 m2 = unionWithKey (\_ x y -> f x y) m1 m2 + +-- | /O(n)/. +-- Union with a combining function. +-- +-- > let f key left_value right_value = (show key) ++ ":" ++ left_value ++ "|" ++ right_value +-- > unionWithKey f (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == fromList [(3, "b"), (5, "5:a|A"), (7, "C")] +unionWithKey :: (Eq k) => (k -> a -> a -> a) -> Map k a -> Map k a -> Map k a +unionWithKey f (Map al) m2 = new_m1 `union` m2 + where + new_m1 = Map $ (\(k,v) -> if member k m2 then (k,f k v (m2 |!| k)) else (k,v)) <$> al + +-- | The union of a list of maps: @(unions == foldl union empty)@. +unions :: (Eq k) => [Map k a] -> Map k a +unions = foldl union empty + +-- | The union of a list of maps, with a combining operation: @(unionsWith f == foldl (unionWith f) empty)@. +unionsWith :: (Eq k) => (a -> a -> a) -> [Map k a] -> Map k a +unionsWith f = foldl (unionWith f) empty + + +-- Difference + + +-- | /O(n*m)/. Difference with a combining function. When two equal keys are encountered, the combining function is applied to the values of these keys. If it returns Nothing, the element is discarded (proper set difference). If it returns (Just y), the element is updated with a new value y +differenceWith :: (Eq k) => (a -> b -> Maybe a) -> Map k a -> Map k b -> Map k a +differenceWith f m1 m2 = differenceWithKey (\_ x y -> f x y) m1 m2 + + +-- | /O(n*m)/. Difference with a combining function. When two equal keys are encountered, the combining function is applied to the key and both values. If it returns Nothing, the element is discarded (proper set difference). If it returns (Just y), the element is updated with a new value y. +differenceWithKey :: (Eq k) => (k -> a -> b -> Maybe a) -> Map k a -> Map k b -> Map k a +differenceWithKey f (Map al) m2 = Map $ Set.mapMaybe (\(k,v) -> if member k m2 then (sequence (k, f k v (m2 |!| k))) else Just (k, v)) al + + +-- Intersection + + +-- | /O(n*m)/. Intersection of two maps. Return data in the first map for the keys existing in both maps. +intersection :: (Eq) k => Map k a -> Map k b -> Map k a +intersection = intersectionWith const + +-- | /O(n*m)/. Intersection with a combining function. +intersectionWith :: (Eq k) => (a -> b -> c) -> Map k a -> Map k b -> Map k c +intersectionWith f m1 m2 = intersectionWithKey (\_ x y -> f x y) m1 m2 + +-- | /O(n*m)/. Intersection with a combining function. +intersectionWithKey :: (Eq k) => (k -> a -> b -> c) -> Map k a -> Map k b -> Map k c +intersectionWithKey f (Map al) m2 = Map $ Set.mapMaybe (\(k,v) -> if member k m2 then Just (k, f k v (m2 |!| k)) else Nothing) al + +-- | Check whether the key sets of two maps are disjoint. +disjoint :: Eq k => Map k a -> Map k b -> Bool +disjoint m1 m2 = null $ intersection m1 m2 + +-- | Relate the keys of one map to the values of the other, by using the values of the former as keys for lookups in the latter. +compose :: Eq b => Map b c -> Map a b -> Map a c +compose = (|.|) + +-- | Compose two functions. If the two functions are not composable, strips the functions until they can compose. +(|.|) :: (Eq b) => Map b c -> Map a b -> Map a c +(|.|) f2 (Map al) = Map $ Set.mapMaybe (\(k,v) -> sequence (k,(f2 |?| v))) al + +-- Traversal + +-- | /O(n)/. Map a function over all values in the map. +map :: (a -> b) -> Map k a -> Map k b +map = fmap + +-- | /O(n)/. Map a function over all values in the map. +mapWithKey :: (k -> a -> b) -> Map k a -> Map k b +mapWithKey f (Map al) = Map $ (\(k,a) -> (k, f k a)) <$> al + +-- | /O(n)/. The function `mapAccum` threads an accumulating argument through the map. +mapAccum :: (Eq k) => (a -> b -> (a, c)) -> a -> Map k b -> (a, Map k c) +mapAccum f d m = mapAccumWithKey (\a k b -> f a b) d m + +-- | /O(n^2)/. The function `mapAccumWithKey` threads an accumulating argument through the map. +mapAccumWithKey :: (Eq k) => (a -> k -> b -> (a, c)) -> a -> Map k b -> (a, Map k c) +mapAccumWithKey f d m = Map <$> set <$> helper d al [] + where + al = mapToList m + helper d [] l = (d,l) + helper d ((k,v):xs) l = helper new xs ((k,val):l) + where + (new,val) = f d k v + + +-- | /O(n)/. Alias of `mapAccumWithKey` for backward compatibility purposes. We don't implement it because order of pairs should not matter. +mapAccumRWithKey :: (Eq k) => (a -> k -> b -> (a, c)) -> a -> Map k b -> (a, Map k c) +mapAccumRWithKey = mapAccumWithKey + + +-- | /O(n)/. @mapKeys f s@ is the map obtained by applying f to each key of s. +mapKeys :: (k1 -> k2) -> Map k1 a -> Map k2 a +mapKeys f (Map al) = Map $ (\(k,v) -> (f k,v)) <$> al + +-- | /O(n^2)/. @mapKeysWith c f s@ is the map obtained by applying f to each key of s. +-- +-- The size of the result may be smaller if f maps two or more distinct keys to the same new key. In this case the associated values will be combined using c. +mapKeysWith :: (Eq k1, Eq k2) => (a -> a -> a) -> (k1 -> k2) -> Map k1 a -> Map k2 a +mapKeysWith f g m = helper al empty + where + al = mapToList m + helper [] r = r + helper ((k,v):xs) r + | g k `member` r = helper xs (insert (g k) (f v (r |!| (g k))) r) + | otherwise = helper xs (insert (g k) v r) + +-- | Alias of `mapKeys` defined for backward compatibility. +mapKeysMonotonic :: (k1 -> k2) -> Map k1 a -> Map k2 a +mapKeysMonotonic = mapKeys + +-- | Eq typeclass must be added. +-- +-- It behaves much like a regular traverse except that the traversing function also has access to the key associated with a value and the values are forced before they are installed in the result map. +traverseWithKey :: (Applicative t, Eq k) => (k -> a -> t b) -> Map k a -> t (Map k b) +traverseWithKey f m = foldrWithKey (\k v ys -> liftA3 insert (pure k) (f k v) ys) (pure mempty) (fromList.mapToList $ m) + +-- | Eq typeclass must be added. Traverse keys/values and collect the Just results. +traverseMaybeWithKey :: (Applicative f, Eq k) => (k -> a -> f (Maybe b)) -> Map k a -> f (Map k b) +traverseMaybeWithKey f m = foldrWithKey (\k v ys -> liftA3 insertMaybe (pure k) (f k v) ys) (pure mempty) (fromList.mapToList $ m) + +-- Folds + +-- | `foldrWithKey` from the left. +foldlWithKey :: (b -> k -> a -> b) -> b -> Map k a -> b +foldlWithKey f d (Map al) = foldl (\b (k,v) -> f b k v) d al + +-- | Fold with key. +foldrWithKey :: (k -> a -> b -> b) -> b -> Map k a -> b +foldrWithKey f d (Map al) = foldr (\(k,v) -> f k v) d al + +-- | Fold the keys and values in the map using the given monoid. +foldMapWithKey :: Monoid m => (k -> a -> m) -> Map k a -> m +foldMapWithKey f (Map al) = foldr (\(k,v) m -> (f k v) <> m) mempty al + + +-- Strict folds + + + +-- | Strict foldr. +foldr' :: (a -> b -> b) -> b -> Map k a -> b +foldr' = Foldable.foldr' + +-- | Strict foldl. +foldl' :: (b -> a -> b) -> b -> Map k a -> b +foldl' = Foldable.foldl' + +-- | Strict `foldrWithKey`. +foldlWithKey' :: (b -> k -> a -> b) -> b -> Map k a -> b +foldlWithKey' f d (Map al) = Foldable.foldl' (\b (k,v) -> f b k v) d al + +-- | Strict `foldrWithKey`. +foldrWithKey' :: (k -> a -> b -> b) -> b -> Map k a -> b +foldrWithKey' f d (Map al) = Foldable.foldr' (\(k,v) -> f k v) d al + + + +-- | A universal combining function. +mergeWithKey :: Eq k => (k -> a -> b -> Maybe c) -> (Map k a -> Map k c) -> (Map k b -> Map k c) -> Map k a -> Map k b -> Map k c +mergeWithKey c f g f1 f2 = Map $ Set.mapMaybe helper ((keys' f1) ||| (keys' f2)) + where + newF1 = f f1 + newF2 = g f2 + helper k + | k `member` f1 && k `member` f2 = sequence (k, c k (f1 |!| k) (f2 |!| k)) + | k `member` f1 = sequence (k, newF1 |?| k) + | k `member` f2 = sequence (k, newF2 |?| k) + + +-- Conversion + + +-- | /O(n^2)/. Transform a function back into its underlying association list. +mapToList :: (Eq k) => Map k v -> AssociationList k v +mapToList (Map al) = nubSetBy (\x y -> (fst x) == (fst y)) al + +-- | /O(n^2)/. Transform a function back into its underlying set of pairs. +mapToSet :: (Eq k) => Map k v -> Set (k,v) +mapToSet m = set $ mapToList m + + +-- | /O(n^2)/. Return all values of the map. Beware that an Eq typeclass must be added. +elems :: (Eq k) => Map k a -> [a] +elems m = snd <$> mapToList m + +-- | /O(n^2)/. Same as `elems` but returns a `Set`. Beware that an Eq typeclass must be added. +elems' :: (Eq k) => Map k a -> Set a +elems' = set.elems + +-- | /O(n^2)/. Alias of `elems'`. +values :: (Eq k) => Map k a -> Set a +values = elems' + +-- | /O(n^2)/. Alias of `elems'`. +image :: (Eq k) => Map k a -> Set a +image = elems' + +-- | /O(n^2)/. Return the keys of a map. Beware that an Eq typeclass must be added. +keys :: (Eq k) => Map k v -> [k] +keys m = fst <$> mapToList m + +-- | /O(n)/. Same as `keys` but returns a `Set`. No Eq typeclass required. +keys' :: Map k v -> Set k +keys' (Map al) = fst <$> al + +-- | /O(n^2)/. Alias of `keys'`. +domain :: Map k a -> Set k +domain = keys' + +-- | Alias of `mapToList` for backward compatibility. Beware that an Eq typeclass must be added. +assocs :: (Eq k) => Map k a -> [(k, a)] +assocs = mapToList + +-- | Alias of `keys'` for backward compatibility. +keysSet :: Map k a -> Set k +keysSet = keys' + +-- | /O(n^2)/. Return the set of values of a map. +elemsSet :: (Eq k) => Map k a -> Set a +elemsSet = values + +-- | /O(n^2)/. Alias of `mapToList` for backward compatibility. Beware that an Eq typeclass must be added. +toList :: (Eq k) => Map k a -> [(k, a)] +toList = mapToList + +-- | Alias of `toList` for backward compatibility. +toAscList :: (Eq k) => Map k a -> [(k, a)] +toAscList = toList + +-- | Alias of `toList` for backward compatibility. +toDescList :: (Eq k) => Map k a -> [(k, a)] +toDescList = toList + + + +-- Filter + + +-- | /O(n)/. Filter all values that satisfy the predicate. +filter :: (a -> Bool) -> Map k a -> Map k a +filter p (Map al) = Map $ Set.filter (\(k,v) -> p v) al + +-- | /O(n)/. Filter all keys/values that satisfy the predicate. +filterWithKey :: (k -> a -> Bool) -> Map k a -> Map k a +filterWithKey p (Map al) = Map $ Set.filter (uncurry p) al + +-- | /O(n*m)/. Restrict a `Map` to only those keys found in a `Set`. +restrictKeys :: Eq k => Map k a -> Set k -> Map k a +restrictKeys m s = filterWithKey (\k v -> k `isIn` s) m + +-- | /O(n*m)/. Remove all keys in a `Set` from a `Map`. +withoutKeys :: Eq k => Map k a -> Set k -> Map k a +withoutKeys m s = filterWithKey (\k v -> not $ k `isIn` s) m + +-- | /O(n)/. Partition the map according to a predicate. The first map contains all elements that satisfy the predicate, the second all elements that fail the predicate. +partition :: (a -> Bool) -> Map k a -> (Map k a, Map k a) +partition p m = (filter p m, filter (not.p) m) + +-- | /O(n)/. Partition the map according to a predicate. The first map contains all elements that satisfy the predicate, the second all elements that fail the predicate. +partitionWithKey :: (k -> a -> Bool) -> Map k a -> (Map k a, Map k a) +partitionWithKey p m = (filterWithKey p m, filterWithKey ((fmap not).p) m) + +-- | /O(n)/. Map values and collect the Just results. +mapMaybe :: (a -> Maybe b) -> Map k a -> Map k b +mapMaybe f m = mapMaybeWithKey (const f) m + +-- | /O(n)/. Map keys/values and collect the Just results. +mapMaybeWithKey :: (k -> a -> Maybe b) -> Map k a -> Map k b +mapMaybeWithKey f (Map al) = Map $ Set.mapMaybe customF al + where + customF (k,v) = sequence (k, f k v) + +-- | /O(n)/. Map values and separate the Left and Right results. +mapEither :: (a -> Either b c) -> Map k a -> (Map k b, Map k c) +mapEither f m = mapEitherWithKey (const f) m + +-- | /O(n)/. Map keys/values and separate the Left and Right results. +mapEitherWithKey :: (k -> a -> Either b c) -> Map k a -> (Map k b, Map k c) +mapEitherWithKey f (Map al) = (Map ls, Map rs) + where + (ls,rs) = Set.mapEither customF al + customF (k,v) + | null result = Left (k,l) + | otherwise = Right (k,r) + where + result = f k v + Left l = result + Right r = result + + + +-- Submap + + +-- | /O(max(m^2,n^2))/. This function is defined as @(isSubmapOf = isSubmapOfBy (==))@. +isSubmapOf :: (Eq k, Eq a) => Map k a -> Map k a -> Bool +isSubmapOf = isSubmapOfBy (==) + +-- | /O(max(m^2,n^2))/. Returns True if the keys of the first map is included in the keys of the second and the predicate evaluation at their value is True. +isSubmapOfBy :: Eq k => (a -> b -> Bool) -> Map k a -> Map k b -> Bool +isSubmapOfBy p m1 m2 = (keys' m1) `isIncludedIn` (keys' m2) && (and $ test <$> keys' m1) + where + test k = p (m1 |!| k) (m2 |!| k) + +-- | /O(max(m^2,n^2))/. This function is defined as @(isProperSubmapOf = isProperSubmapOfBy (==))@. +isProperSubmapOf :: (Eq k, Eq a) => Map k a -> Map k a -> Bool +isProperSubmapOf = isProperSubmapOfBy (==) + +-- | /O(max(m^2,n^2))/. Returns True if the keys of the first map is strictly included in the keys of the second and the predicate evaluation at their value is True. +isProperSubmapOfBy :: Eq k => (a -> b -> Bool) -> Map k a -> Map k b -> Bool +isProperSubmapOfBy p m1 m2 = (keys' m1) `Set.isProperSubsetOf` (keys' m2) && (and $ test <$> keys' m1) + where + test k = p (m1 |!| k) (m2 |!| k) + + + +-- Indexed + + +-- | /O(n^2)/. Lookup the index of a key, which is its zero-based index in the sequence. The index is a number from 0 up to, but not including, the size of the map. +lookupIndex :: Eq k => k -> Map k a -> Maybe Int +lookupIndex k m = L.elemIndex k (keys m) + +-- | /O(n^2)/. Return the index of a key, which is its zero-based index in the sequence. The index is a number from 0 up to, but not including, the size of the map. Calls error when the key is not a member of the map. +findIndex :: Eq k => k -> Map k a -> Int +findIndex k m + | null index = error "WeakSet.findIndex: element is not in the set" + | otherwise = i + where + index = lookupIndex k m + Just i = index + +-- | /O(n^2)/. Retrieve an element by its index, i.e. by its zero-based index in the sequence. If the index is out of range (less than zero, greater or equal to size of the map), error is called. +elemAt :: Eq k => Int -> Map k a -> (k, a) +elemAt i m + | i < 0 || i >= (length xs) = error "WeakSet.elemAt: index out of range" + | otherwise = (L.!!) xs i + where + xs = mapToList m + +-- | Helper function for updateAt. +updateListAt :: Int -> (a -> Maybe a) -> [a] -> [a] +updateListAt _ _ [] = [] +updateListAt 0 f (x : xs) + | null result = xs + | otherwise = r : xs + where + result = f x + Just r = result +updateListAt n f (x : xs) = x : updateListAt (n-1) f xs + +-- | /O(n^2)/. Update the element at index. Calls error when an invalid index is used. +updateAt :: Eq k => (k -> a -> Maybe a) -> Int -> Map k a -> Map k a +updateAt f i m = Map $ set $ updateListAt i (\(k,v) -> sequence (k, f k v)) (mapToList m) + +-- | /O(n^2)/. Delete the element at index, i.e. by its zero-based index in the sequence. If the index is out of range (less than zero, greater or equal to size of the map), error is called. +deleteAt :: (Eq k) => Int -> Map k a -> Map k a +deleteAt i m = Map $ set $ helper i al + where + al = mapToList m + helper _ [] = [] + helper 0 (x:xs) = xs + helper n (x:xs) = helper (n-1) xs + + +-- Others + + + +-- | /O(n)/. Return the identity function associated to a `Set`. +idFromSet :: Set a -> Map a a +idFromSet set = Map $ (\x -> (x,x)) <$> set + + +-- | /O(n)/. Memorize a Haskell function on a given finite domain. Alias of `fromSet`. +memorizeFunction :: (k -> v) -> Set k -> Map k v +memorizeFunction f xs = Map $ (\k -> (k, f k)) <$> xs + + +
+ src/Data/WeakMap/Safe.hs view
@@ -0,0 +1,27 @@+{-| Module : WeakSets +Description : Non-clashing functions for `Map`s. +Copyright : Guillaume Sabbagh 2022 +License : LGPL-3.0-or-later +Maintainer : guillaumesabbagh@protonmail.com +Stability : experimental +Portability : portable + +Non-clashing functions for `Map`s. +-} + +module Data.WeakMap.Safe +( + weakMap -- the smart constructor for `Map` + , (|?|) + , (|!|) + , (|.|) + , idFromSet + , memorizeFunction + , elems' + , keys' + , domain + , image +) +where + import Data.WeakMap +
+ src/Data/WeakSet.hs view
@@ -0,0 +1,518 @@+{-| Module : WeakSets +Description : Weak sets are sets of objects which do not have to be orderable. They are homogeneous, they can only contain a single type of object. They are more flexible than Data.Set but slower. +Copyright : Guillaume Sabbagh 2022 +License : LGPL-3.0-or-later +Maintainer : guillaumesabbagh@protonmail.com +Stability : experimental +Portability : portable + +Weak sets are sets of objects which do not have to be orderable. They are homogeneous, they can only contain a single type of object. + +They are more flexible than Data.Set, they are quicker at insertion but slower at retrieving elements because the datatype only assumes its components are equatable. + +We use this datatype because most of the datatypes we care about are not orderable. It also allows to define a Functor, Applicative and Monad structure on sets. + +Almost all Data.WeakSet functions are implemented so that you can replace a Data.Set import such as + +> import Data.Set (Set) +> import qualified Data.Set as Set + +by a Data.WeakSet import such as + +> import Data.WeakSet (Set) +> import qualified Data.WeakSet as Set + +without breaking anything in your code. + +The only functions for which this would fail are the functions converting sets back into list (they require the Eq typeclass unlike in Data.Set). `size` is one of them. + +If a function really requires the Ord typeclass to even make sense, then it is not defined in this package, you should use Data.Set. + +Note that, just like in Data.Set, the implementation is generally left-biased. Functions that take two sets as arguments and combine them, such as union and intersection, prefer the entries in the first argument to those in the second. + +Functions with non colliding names are defined in Data.WeakSet.Safe. Inline functions are written between pipes @|@. + +This module is intended to be imported qualified, to avoid name clashes with Prelude functions, except for functions in Data.WeakSet.Safe, e.g. + +> import Data.WeakSet (Set) +> import qualified Data.WeakSet as Set +> import Data.WeakSet.Safe + +Unlike Data.Set, we defer the removing of duplicate elements to the conversion back to a list. It is therefore a valid Functor, Applicative and Monad. This allows to create weak sets by comprehension if you include the MonadComprehensions pragma at the beginning of your file. + +Beware if the set is supposed to contain a lot of duplicate elements, you should purge them yourself by transforming the set into a list and back into a set. The time complexity is always given in function of the number of elements in the set including the duplicate elements. + +-} + +module Data.WeakSet +( + Set + + -- * Construction + , empty + , singleton + , set + , fromList + , fromAscList + , fromDescList + , fromDistinctAscList + , fromDistinctDescList + , powerSet + + -- * Operators + , (|&|) + , (|||) + , (|*|) + , (|+|) + , (|-|) + , (|^|) + + -- * Insertion + , insert + + -- * Deletion + , delete + + -- * Generalized insertion/deletion + + , alterF + + -- -- * Query + , isIn + , member + , notMember + , cardinal + , size + , isIncludedIn + , isSubsetOf + , isProperSubsetOf + , disjoint + + -- * Combine + , union + , unions + , difference + , (\\) + , intersection + , cartesianProduct + , disjointUnion + + -- * Filter + , filter + , partition + + -- * Indexed + , lookupIndex + , findIndex + , elemAt + , deleteAt + , take + , drop + , splitAt + + -- * Map + , map + , mapMonotonic + + -- * Folds + -- ** Strict folds + , foldr' + , foldl' + + -- * Conversion + + -- ** List + , setToList + , toList + , nubSetBy + + -- * Maybe interaction + , setToMaybe + , maybeToSet + , catMaybes + , mapMaybe + + -- * Either interaction + , mapEither + , catEither + + -- * Others + , traverseSet + , sequenceSet + +) where +import Prelude hiding (filter, splitAt, drop, take, map) +import qualified Data.List as L +import qualified Data.Maybe as M +import Control.Applicative (liftA2) +import qualified Data.Foldable as Foldable + +-- | A weak set is a list of values such that the duplicate elements and the order of the elements are disregarded. +-- +-- To force these constraints, the `Set` constructor is abstract and is not exported. The only way to construct a set is to use the smart constructor `fromList` or `set` which ensures the previous conditions. +data Set a = Set [a] + +instance Foldable Set where + foldr f d (Set xs) = foldr f d xs + +instance (Eq a) => Eq (Set a) where + x == y = x `isIncludedIn` y && y `isIncludedIn` x + +instance Semigroup (Set a) where + (Set xs) <> (Set ys) = set $ xs <> ys + +instance Monoid (Set a) where + mempty = Set [] + +instance Functor Set where + fmap f (Set xs) = Set $ f <$> xs + +instance Applicative Set where + pure x = Set [x] + (<*>) (Set fs) (Set xs) = Set $ fs <*> xs + +instance Monad Set where + (>>=) (Set xs) f = Set $ xs >>= (unsafeSetToList.f) + +instance (Show a) => Show (Set a) where + show (Set xs) = "(set "++show xs++")" + + +-- Construction + + +-- | Alias of mempty. Defined for backward compatibility with Data.Set. +empty :: Set a +empty = mempty + +-- | Alias of pure. Defined for backward compatibility with Data.Set. +singleton :: a -> Set a +singleton = pure + +-- | /O(1)/. The smart constructor of sets. This is the only way of instantiating a `Set` with `fromList`. +-- +-- We prefer the smart constructor `set` because its name does not collide with other data structures. +set :: [a] -> Set a +set = Set + +-- | /O(1)/. This smart constructor is provided to allow backward compatibility with Data.Set. +fromList :: [a] -> Set a +fromList = set + +-- | /O(1)/. Defined for backward compatibility with Data.Set. +fromAscList :: [a] -> Set a +fromAscList = set + +-- | /O(1)/. Defined for backward compatibility with Data.Set. +fromDescList :: [a] -> Set a +fromDescList = set + +-- | /O(1)/. Defined for backward compatibility with Data.Set. +fromDistinctAscList :: [a] -> Set a +fromDistinctAscList = set + +-- | /O(1)/. Defined for backward compatibility with Data.Set. +fromDistinctDescList :: [a] -> Set a +fromDistinctDescList = set + +-- | Return the set of all subsets of a given set. +-- +-- Example : +-- +-- @ +-- ghci> powerSet $ set [1,2,3] +-- (set [(set []),(set [1]),(set [2]),(set [1,2]),(set [3]),(set [1,3]),(set [2,3]),(set [1,2,3])]) +-- @ +powerSet :: Set a -> Set (Set a) +powerSet (Set xs) = Set $ Set <$> L.subsequences xs + + +-- Insertion + + +-- | O(1). Insert an element in a set. If the set already contains an element equal to the given value, it is replaced with the new value. +insert :: a -> Set a -> Set a +insert x (Set xs) = Set (x:xs) + + +-- Deletion + + +-- | O(n). Delete an element from a set. +delete :: Eq a => a -> Set a -> Set a +delete x (Set xs) = Set $ L.filter (/= x) xs + + +-- Generalized deletion/insertion + + +-- | O(n). @(alterF f x s)@ can delete or insert x in s depending on whether an equal element is found in s. +-- +-- Note that unlike insert, alterF will not replace an element equal to the given value. +alterF :: (Eq a, Functor f) => (Bool -> f Bool) -> a -> Set a -> f (Set a) +alterF f x s + | x `isIn` s = (\b -> if b then s else delete x s) <$> (f True) + | otherwise = (\b -> if b then insert x s else s) <$> (f False) + + +-- Query + + +-- | /O(n)/. Return wether an element is in a set. +isIn :: (Eq a) => a -> Set a -> Bool +isIn x = (elem x).unsafeSetToList + +-- | /O(n)/. Alias of `isIn`. Defined for backward compatibility with Data.Set. +member :: Eq a => a -> Set a -> Bool +member = isIn + +-- | /O(n)/. Negation of `member`. Defined for backward compatibility with Data.Set. +notMember :: Eq a => a -> Set a -> Bool +notMember x s = not $ member x s + +-- | /O(n^2)/. Size of a set. +cardinal :: (Eq a) => Set a -> Int +cardinal = length.setToList + +-- | /O(n)/. Size of a set. +size :: (Eq a) => Set a -> Int +size = cardinal + +-- | /O(n^2)/. Return a boolean indicating if a `Set` is included in another one. +isIncludedIn :: (Eq a) => Set a -> Set a -> Bool +(Set []) `isIncludedIn` _ = True +(Set (x:xs)) `isIncludedIn` (Set ys) + | x `elem` ys = (Set xs) `isIncludedIn` (Set ys) + | otherwise = False + +-- | /O(n^2)/. Return a boolean indicating if a `Set` is included in another one. +isSubsetOf :: (Eq a) => Set a -> Set a -> Bool +isSubsetOf = isIncludedIn + +-- | /O(n^2)/. x is a proper subset of y if x is included in y and x is different from y. +isProperSubsetOf :: (Eq a) => Set a -> Set a -> Bool +isProperSubsetOf x y = x /= y && x `isIncludedIn` y + +-- | /O(n^2)/. Check whether two sets are disjoint (i.e., their intersection is empty). +disjoint :: (Eq a) => Set a -> Set a -> Bool +disjoint x y = null $ x `intersection` y + + +-- Combine + + +-- | /O(n)/. The union of two sets, preferring the first set when equal elements are encountered. +union :: Set a -> Set a -> Set a +union (Set xs) (Set ys) = Set (xs ++ ys) + +-- | The union of the sets in a Foldable structure. +unions :: (Foldable f) => f (Set a) -> Set a +unions = L.foldl union empty + +-- | /O(n*m)/. Difference of two sets. +difference :: (Eq a) => Set a -> Set a -> Set a +difference (Set xs) y = Set $ L.filter (not.(`isIn` y)) xs + +-- | See difference. +(\\) :: (Eq a) => Set a -> Set a -> Set a +(\\) = difference + +-- | /O(m*n)/. Return the intersection of two sets. Elements of the result come from the first set. +intersection :: (Eq a) => Set a -> Set a -> Set a +intersection (Set xs) y = Set $ L.filter (`isIn` y) xs + +-- | /O(m*n)/. Return the cartesian product of two sets. +cartesianProduct :: Set a -> Set b -> Set (a,b) +cartesianProduct (Set xs) (Set ys) = Set $ [(x,y) | x <- xs, y <- ys] + +-- | /O(n)/. Return the disjoint union of two sets. +disjointUnion :: Set a -> Set b -> Set (Either a b) +disjointUnion (Set xs) (Set ys) = Set $ [Left x | x <- xs] ++ [Right y | y <- ys] + + +-- Filter + + +-- | O(n). Filter all elements that satisfy the predicate. +filter :: (a -> Bool) -> Set a -> Set a +filter p (Set xs) = Set $ L.filter p xs + +-- | O(n). Partition the set into two sets, one with all elements that satisfy the predicate and one with all elements that don't satisfy the predicate. See also `split`. +partition :: (a -> Bool) -> Set a -> (Set a, Set a) +partition p (Set xs) = (Set $ L.filter p xs, Set $ L.filter (not.p) xs) + + +-- Indexed + + +-- | O(n^2). Lookup the index of an element, which is its zero-based index in the sorted sequence of elements. The index is a number from 0 up to, but not including, the size of the set. +lookupIndex :: (Eq a) => a -> Set a -> Maybe Int +lookupIndex k x = L.elemIndex k (setToList x) + +-- | O(n^2). Return the index of an element, which is its zero-based index in the sorted sequence of elements. The index is a number from 0 up to, but not including, the size of the set. Calls error when the element is not a member of the set. +findIndex :: (Eq a) => a -> Set a -> Int +findIndex k x + | null index = error "WeakSet.findIndex: element is not in the set" + | otherwise = i + where + index = lookupIndex k x + Just i = index + +-- | O(n^2). Retrieve an element by its index, i.e. by its zero-based index in the sorted sequence of elements. If the index is out of range (less than zero, greater or equal to size of the set), `error` is called. +elemAt :: (Eq a) => Int -> Set a -> a +elemAt i s + | i < 0 || i >= (length xs) = error "WeakSet.elemAt: index out of range" + | otherwise = (L.!!) xs i + where + xs = setToList s + +-- | O(n). Delete the element at index, i.e. by its zero-based index in the sorted sequence of elements. If the index is out of range (less than zero, greater or equal to size of the set), error is called. +deleteAt :: (Eq a) => Int -> Set a -> Set a +deleteAt i s = filter (/= (elemAt i s)) s + +-- | O(n^2). Take a given number of elements in order. +take :: (Eq a) => Int -> Set a -> Set a +take i s = Set $ L.take i (setToList s) + +-- | O(n^2). Drop a given number of elements in order. +drop :: (Eq a) => Int -> Set a -> Set a +drop i s = Set $ L.drop i (setToList s) + +-- | O(n^2). Split a set at a particular index. +splitAt :: (Eq a) => Int -> Set a -> (Set a, Set a) +splitAt i s = (Set x, Set y) + where + (x,y) = L.splitAt i (setToList s) + + +-- Map + + +-- | /O(n)/. Alias of `fmap` for backward compatibility with Data.Set. Note that a WeakSet is a functor. +map :: (a -> b) -> Set a -> Set b +map = fmap + +-- | /O(n)/. Alias of `fmap` for backward compatibility with Data.Set. +mapMonotonic :: (a -> b) -> Set a -> Set b +mapMonotonic = fmap + + +-- Folds + + +-- | Strict foldr. +foldr' :: (a -> b -> b) -> b -> Set a -> b +foldr' f d (Set xs) = Foldable.foldr' f d xs + +-- | Strict foldl. +foldl' :: (a -> b -> a) -> a -> Set b -> a +foldl' f d (Set xs) = Foldable.foldl' f d xs + + +-- Conversion + + +-- | /O(1)/. Gives the underlying list of a set without removing duplicates, this function is not exported. +unsafeSetToList :: Set a -> [a] +unsafeSetToList (Set xs) = xs + +-- | /O(n^2)/. Transform a `Set` back into a list, the list returned does not have duplicate elements, the order of the original list holds. +setToList :: (Eq a) => Set a -> [a] +setToList (Set xs) = L.nub xs + +-- | /O(n^2)/. Alias of `setToList` for backward compatibility with Data.Set. +toList :: (Eq a) => Set a -> [a] +toList = setToList + + +-- Maybe interactions + + +-- | /O(1)/. Set version of listToMaybe. +setToMaybe :: Set a -> Maybe a +setToMaybe = (M.listToMaybe).unsafeSetToList + +-- | /O(1)/. Set version of maybeToList. +maybeToSet :: Maybe a -> Set a +maybeToSet x = Set $ (M.maybeToList) x + +-- | /O(n)/. Set version of catMaybes. Only keeps the Just values of a set and extract them. +catMaybes :: Set (Maybe a) -> Set a +catMaybes = set.(M.catMaybes).unsafeSetToList + +-- | /O(n)/. Set version of mapMaybe. A map which throws out elements which are mapped to nothing. +mapMaybe :: (a -> Maybe b) -> Set a -> Set b +mapMaybe f = set.(M.mapMaybe f).unsafeSetToList + + +-- Either interactions + + +-- | /O(n)/. Map a function to a set and separate Left and Right values. +catEither :: Set (Either a b) -> (Set a, Set b) +catEither (Set []) = (empty,empty) +catEither (Set (x:xs)) + | null x = (insert l ls, rs) + | otherwise = (ls, insert r rs) + where + (ls,rs) = catEither (Set xs) + Right r = x + Left l = x + + +-- | /O(n)/. Map a function to a set, return a couple composed of the set of left elements and the set of right elements. +mapEither :: (a -> Either b c) -> Set a -> (Set b, Set c) +mapEither _ (Set []) = (empty, empty) +mapEither f (Set (x:xs)) + | null result = (insert l ls, rs) + | otherwise = (ls, insert r rs) + where + (ls,rs) = mapEither f (Set xs) + result = f x + Left l = result + Right r = result + + +-- Other + + +-- | /O(n^2)/. Remove duplicates in the set using your own equality function. +nubSetBy :: (a -> a -> Bool) -> Set a -> [a] +nubSetBy f (Set xs) = L.nubBy f xs + + +-- Operators + + +-- | Alias of `intersection`. +(|&|) :: (Eq a) => Set a -> Set a -> Set a +(|&|) = intersection + +-- | Alias of `union`. +(|||) :: Set a -> Set a -> Set a +(|||) = union + +-- | Alias of `cartesianProduct`. +(|*|) :: Set a -> Set b -> Set (a,b) +(|*|) = cartesianProduct + +-- | Alias of `disjointUnion`. +(|+|) :: Set a -> Set b -> Set (Either a b) +(|+|) = disjointUnion + +-- | Returns the cartesian product of a set with itself n times. +(|^|) :: (Num a, Eq a) => Set a -> a -> Set [a] +(|^|) _ 0 = Set [[]] +(|^|) s n = (:) <$> s <*> (s |^| (n-1)) + +-- | Alias of `difference`. +(|-|) :: (Eq a) => Set a -> Set a -> Set a +(|-|) = difference + +-- | Set is not a Traversable because of the Eq typeclass requirement. +traverseSet :: (Applicative f, Eq a) => (a -> f b) -> Set a -> f (Set b) +traverseSet f s = foldr (\x ys -> liftA2 insert (f x) ys) (pure mempty) (set.setToList $ s) + +-- | Set is not a Traversable because of the Eq typeclass requirement. +sequenceSet :: (Applicative f, Eq (f a)) => Set (f a) -> f (Set a) +sequenceSet (Set xs) = Set <$> sequenceA (L.nub xs)
+ src/Data/WeakSet/Safe.hs view
@@ -0,0 +1,30 @@+{-| Module : WeakSets +Description : Non-clashing functions for `Set`s. +Copyright : Guillaume Sabbagh 2022 +License : LGPL-3.0-or-later +Maintainer : guillaumesabbagh@protonmail.com +Stability : experimental +Portability : portable + +Non-clashing functions for `Set`s. +-} + +module Data.WeakSet.Safe +( + set, -- the smart constructor for `Set` + -- * Set related functions + setToList, + isIncludedIn, + cardinal, + isIn, + (|&|), + (|||), + (|*|), + (|+|), + (|-|), + (|^|), + nubSetBy, +) +where + import Data.WeakSet +
− src/Data/WeakSets/HomogeneousFunction.hs
@@ -1,235 +0,0 @@-{-| Module : WeakSets -Description : Homogeneous functions are functions between `HomogeneousSet`s. They are more flexible than Data.Map because they do not require the keys to be orderable. -Copyright : Guillaume Sabbagh 2022 -License : LGPL-3.0-or-later -Maintainer : guillaumesabbagh@protonmail.com -Stability : experimental -Portability : portable - -Homogeneous functions are functions between `HomogeneousSet`s. - -They are more flexible than Data.Map because they do not require the keys to be orderable. - -The datatype only assumes its keys are equatable, it is therefore slower than the Data.Map datatype. - -We use this datatype because most of the datatypes we care about are not orderable. - -Inline functions related to homogeneous functions are written between pipes @|@. - -Function names should not collide with Prelude but may collide with Data.Map. --} - -module Data.WeakSets.HomogeneousFunction -( - -- * Function datatype and smart constructor - AssociationList(..), - Function, -- abstract type, the smart constructor is `function` - function, -- the smart constructor for `Function` - -- * Function related functions - domain, - image, - idFromSet, - (|.|), - -- * Query - size, - member, - notMember, - (|?|), - (|!|), - findWithDefault, - -- * Construction - -- ** Insertion - insert, - insertWith, - insertWithKey, - -- ** Delete/Update - delete, - adjust, - adjustWithKey, - alter, - -- * Combine - -- ** Union - union, - -- * Traversal - mapKeys, - -- * Conversion - keys, - elems, - functionToSet, - memorizeFunction, -) -where - import Data.WeakSets.HomogeneousSet - - -- | A function of homogeneous sets. It is a set of pairs (key,value) such that their should only be one pair with a given key. - -- - -- It is an abstract type, the smart constructor is `function`. - data Function k v = Function (Set (k,v)) deriving (Eq) - - instance (Show k, Show v) => Show (Function k v) where - show (Function al) = "(function "++show al++")" - - instance Semigroup (Function k v) where - (Function al1) <> (Function al2) = Function $ al1 <> al2 - - instance Monoid (Function k v) where - mempty = Function (set []) - - instance Foldable (Function k) where - foldr f d (Function al) = foldr (\(k,v) -> f v) d al - - instance Functor (Function k) where - fmap f (Function al) = Function $ (\(k,v) -> (k,f v)) <$> al - - -- | An association list is a list of pairs (key,value). - type AssociationList k v = [(k,v)] - - -- | /O(1)/. The smart constructor of functions. This is the only way of instantiating a `Function`. - -- - -- Takes an association list and returns a function which maps to each key the value associated. - -- - -- If several pairs have the same keys, they are kept until the user wants an association list back. - function :: AssociationList k v -> Function k v - function al = Function $ set $ al - - -- | /O(n)/. Return the domain of a function. - domain :: Function k v -> Set k - domain (Function al) = fst <$> al - - -- | /O(n)/. Return the image of a function. The image of a function is the set of values which are reachable by applying the function. - image :: Function k v -> Set v - image (Function al) = snd <$> al - - -- | /O(n)/. Return the identity function associated to a `Set`. - idFromSet :: Set a -> Function a a - idFromSet set = Function $ (\x -> (x,x)) <$> set - - -- | Compose two functions. If the two functions are not composable, strips the functions until they can compose. - (|.|) :: (Eq a, Eq b) => Function b c -> Function a b -> Function a c - (|.|) f2 f1 = Function $ set [(k,(f2 |!| (f1 |!| k))) | k <- (setToList.domain $ f1), f1 |!| k `isIn` (domain f2)] - -{-------------------------------------------------------------------- - Query ---------------------------------------------------------------------} - - -- | /O(n)/. The number of entries in the function. - size :: (Eq k) => Function k v -> Int - size f = length.setToList.keys $ f - - -- | /O(n)/. Return wether a key is in the function domain or not. - member :: (Eq k) => Function k v -> k -> Bool - member f k = k `isIn` (domain f) - - -- | /O(n)/. Negation of member. - notMember :: (Eq k) => Function k v -> k -> Bool - notMember f k = not $ member f k - - -- | /O(n)/. Apply a function to a given value. If the function is not defined on the given value returns `Nothing`, otherwise returns `Just` the image. - -- - -- This function is like `lookup` in Data.Map for function (the order of the argument are reversed though). - (|?|) :: (Eq k) => Function k v -> k -> Maybe v - (|?|) (Function al) key = setToMaybe.catMaybesToSet $ (\(k,v) -> if k == key then Just v else Nothing) <$> al - - -- | /O(n)/. Unsafe version of `(|?|)`. - -- - -- This function is like `(!)` in Data.Map for function. - (|!|) :: (Eq k) => Function k v -> k -> v - (|!|) f key - | null safeResult = error "Function applied on a value not in the domain." - | otherwise = result - where - safeResult = f |?| key - Just result = safeResult - - -- | /O(n)/. Apply a function to a given value, if the value is in the domain returns the image, otherwise return a default value. - -- - -- This function is like `findWithDefault` in Data.Map for function (the order of the argument are reversed though). - findWithDefault :: (Eq k) => Function k v -> v -> k -> v - findWithDefault f d key - | null safeResult = d - | otherwise = result - where - safeResult = f |?| key - Just result = safeResult - -{-------------------------------------------------------------------- - Insertion ---------------------------------------------------------------------} - - -- | O(1). Insert a new key and value in the function. If the key is already present in the function, the associated value is replaced with the supplied value. insert is equivalent to insertWith const. - insert :: k -> v -> Function k v -> Function k v - insert k v (Function al) = Function $ (set [(k,v)]) ||| al - - -- | O(n). Insert with a function, combining new value and old value. insertWith f key value mp will insert the pair (key, value) into mp if key does not exist in the function. If the key does exist, the function will insert the pair (key, f new_value old_value). - insertWith :: (Eq k) => (v -> v -> v) -> k -> v -> Function k v -> Function k v - insertWith comb k v f - | null prev = insert k v f - | otherwise = insert k (comb v prev_value) f - where - prev = f |?| k - Just prev_value = prev - - -- | O(n). Insert with a function, combining key, new value and old value. insertWithKey f key value mp will insert the pair (key, value) into mp if key does not exist in the function. If the key does exist, the function will insert the pair (key,f key new_value old_value). Note that the key passed to f is the same key passed to insertWithKey. - insertWithKey :: Eq k => (k -> a -> a -> a) -> k -> a -> Function k a -> Function k a - insertWithKey comb k v f - | null prev = insert k v f - | otherwise = insert k (comb k v prev_value) f - where - prev = f |?| k - Just prev_value = prev - -{-------------------------------------------------------------------- - Conversion ---------------------------------------------------------------------} - - -- | /O(n)/. Transform a function back into its underlying association list. - functionToSet :: (Eq k) => Function k v -> Set (k,v) - functionToSet (Function al) = nubSetBy (\x y -> (fst x) == (fst y)) al - - -- | /O(n)/. Alias of domain. - keys :: Function k v -> Set k - keys = domain - - -- | /O(n)/. Alias of image. - elems :: Function k v -> Set v - elems = image - - -- | /O(n)/. Memorize a Haskell function on a given finite domain. - memorizeFunction :: (k -> v) -> Set k -> Function k v - memorizeFunction f xs = Function $ (\k -> (k, f k)) <$> xs - -{-------------------------------------------------------------------- - Delete/Update ---------------------------------------------------------------------} - -- | O(n). Delete a key and its value from the function. When the key is not a member of the function, the original function is returned. - delete :: Eq k => k -> Function k a -> Function k a - delete key (Function al) = Function $ filterSet (\(k,v) -> key /= k) al - - -- | O(n). Update a value at a specific key with the result of the provided function. When the key is not a member of the function, the original function is returned. - adjust :: Eq k => (a -> a) -> k -> Function k a -> Function k a - adjust func key (Function al) = Function $ (\(k,v) -> if key == k then (k, func v) else (k,v)) <$> al - - -- | O(n). Adjust a value at a specific key. When the key is not a member of the function, the original function is returned. - adjustWithKey :: Eq k => (k -> a -> a) -> k -> Function k a -> Function k a - adjustWithKey func key (Function al) = Function $ (\(k,v) -> if key == k then (k, func k v) else (k,v)) <$> al - - -- | O(n). The expression (`alter` f k function) alters the value x at k, or absence thereof. alter can be used to insert, delete, or update a value in a `Function`. In short : `lookup` k (`alter` f k m) = f (`lookup` k m). - alter :: Eq k => (Maybe a -> Maybe a) -> k -> Function k a -> Function k a - alter func key f - | null lookupKey = insert key unpackedImageNothing f - | null result = delete key f - | otherwise = adjust (const unpackedResult) key f - where - lookupKey = f |?| key - result = func lookupKey - Just unpackedResult = result - Just unpackedImageNothing = func Nothing - - -- | /O(n)/. Map a function over the keys of a function. - mapKeys :: (k1 -> k2) -> Function k1 v -> Function k2 v - mapKeys f (Function al) = Function $ (\(k,v) -> (f k,v)) <$> al - - - -- | /O(n)/. The expression (`union` t1 t2) takes the left-biased union of t1 and t2. It prefers t1 when duplicate keys are encountered. - union :: Eq k => Function k a -> Function k a -> Function k a - union (Function al1) (Function al2) = Function $ al1 ||| al2
− src/Data/WeakSets/HomogeneousSet.hs
@@ -1,163 +0,0 @@-{-| Module : WeakSets -Description : Homogeneous sets are sets which can contain only one type of values. They are more flexible than Data.Set because they do not require the objects contained to be orderable. -Copyright : Guillaume Sabbagh 2022 -License : LGPL-3.0-or-later -Maintainer : guillaumesabbagh@protonmail.com -Stability : experimental -Portability : portable - -Homogeneous sets are sets which can contain only one type of values. - -They are more flexible than Data.Set because they do not require the objects contained to be orderable. - -The datatype only assumes its components are equatable, it is therefore slower than the Data.Set datatype. - -We use this datatype because most of the datatypes we care about are not orderable. - -Inline functions related to homogeneous sets are written between pipes @|@. - -Function names should not collide with Prelude but may collide with Data.Set. --} - -module Data.WeakSets.HomogeneousSet -( - -- * Set datatype and smart constructor - Set, -- abstract type, the smart constructor is `set` - set, -- the smart constructor for `Set` - -- * Set related functions - setToList, - isIncludedIn, - cardinal, - isIn, - (|&|), - (|||), - (|*|), - (|+|), - (|-|), - (|^|), - powerSet, - filterSet, - nubSetBy, - -- * Functions to work with `Maybe` - setToMaybe, - maybeToSet, - catMaybesToSet, - mapMaybeToSet, -) -where - import Data.List (intercalate, nub, nubBy, intersect, union, (\\), subsequences) - import Data.Maybe - - -- | A homogeneous set is a list of values. - -- - -- The only differences are that we don't want duplicate elements and we don't need the order of the list elements. - -- - -- To force these constraints, the `Set` constructor is abstract and is not exported. The only way to construct a set is to use the smart constructor `set` which ensures the previous conditions. - data Set a = Set [a] - - -- | /O(1)/. The smart constructor of sets. This is the only way of instantiating a `Set`. - -- - -- If several elements are equal, they are kept until the user wants a list back. - set :: [a] -> Set a - set xs = Set xs - - instance (Show a) => Show (Set a) where - show (Set xs) = "(set "++show xs++")" - - -- | /O(n^2)/. Return a boolean indicating if a `Set` is included in another one. - isIncludedIn :: (Eq a) => Set a -> Set a -> Bool - (Set []) `isIncludedIn` _ = True - (Set (x:xs)) `isIncludedIn` (Set ys) - | x `elem` ys = (Set xs) `isIncludedIn` (Set ys) - | otherwise = False - - instance (Eq a) => Eq (Set a) where - x == y = x `isIncludedIn` y && y `isIncludedIn` x - - instance Semigroup (Set a) where - (Set xs) <> (Set ys) = set $ xs <> ys - - instance Monoid (Set a) where - mempty = Set [] - - instance Foldable Set where - foldr f d (Set xs) = foldr f d xs - - instance Functor Set where - fmap f (Set xs) = Set $ f <$> xs - - instance Applicative Set where - pure x = Set [x] - (<*>) (Set fs) (Set xs) = Set $ fs <*> xs - - instance Monad Set where - (>>=) (Set xs) f = Set $ xs >>= (unsafeSetToList.f) - - -- | /O(n)/. Transform a `Set` back into a list, the list returned does not have duplicate elements, the order of the original list holds. - setToList :: (Eq a) => Set a -> [a] - setToList (Set xs) = nub xs - - -- | /O(1)/. Gives the underlying list of a set without removing duplicates, this function is not exported. - unsafeSetToList :: Set a -> [a] - unsafeSetToList (Set xs) = xs - - -- | /O(n)/. Size of a set. - cardinal :: (Eq a) => Set a -> Int - cardinal = length.setToList - - -- | /O(n)/. Return wether an element is in a set. - isIn :: (Eq a) => a -> Set a -> Bool - isIn x = (elem x).unsafeSetToList - - -- | /O(n*m)/. Return the intersection of two sets. - (|&|) :: (Eq a) => Set a -> Set a -> Set a - (|&|) (Set xs) (Set ys) = Set $ xs `intersect` ys - - -- | /O(n)/. Return the union of two sets. - (|||) :: Set a -> Set a -> Set a - (|||) (Set xs) (Set ys) = Set $ xs ++ ys - - -- | /O(n*m)/. Return the cartesian product of two sets. - (|*|) :: Set a -> Set b -> Set (a,b) - (|*|) (Set xs) (Set ys) = Set $ [(x,y) | x <- xs, y <- ys] - - -- | /O(n)/. Return the disjoint union of two sets. - (|+|) :: Set a -> Set b -> Set (Either a b) - (|+|) (Set xs) (Set ys) = Set $ [Left x | x <- xs] ++ [Right y | y <- ys] - - -- | Returns the cartesian product of a set with itself n times. - (|^|) :: (Num a, Eq a) => Set a -> a -> Set [a] - (|^|) _ 0 = Set [[]] - (|^|) s n = (:) <$> s <*> (s |^| (n-1)) - - -- | /O(n*m)/. Return the difference of two sets. - (|-|) :: (Eq a) => Set a -> Set a -> Set a - (|-|) (Set xs) (Set ys) = Set $ xs \\ ys - - -- | Return the set of all subsets of a given set. - powerSet :: Set a -> Set (Set a) - powerSet (Set xs) = Set $ Set <$> subsequences xs - - -- | /O(n)/. Filter a set according to a condition. - filterSet :: (a -> Bool) -> Set a -> Set a - filterSet f (Set xs) = Set $ filter f xs - - -- | /O(1)/. Set version of listToMaybe. - setToMaybe :: Set a -> Maybe a - setToMaybe = listToMaybe.unsafeSetToList - - -- | /O(1)/. Set version of maybeToList. - maybeToSet :: Maybe a -> Set a - maybeToSet x = Set $ maybeToList x - - -- | /O(n)/. Set version of catMaybes. - catMaybesToSet :: Set (Maybe a) -> Set a - catMaybesToSet = set.catMaybes.unsafeSetToList - - -- | /O(n)/. Set version of mapMaybe. - mapMaybeToSet :: (a -> Maybe b) -> Set a -> Set b - mapMaybeToSet f = set.(mapMaybe f).unsafeSetToList - - -- | /O(n)/. Remove duplicates in the set using your own equality function. - nubSetBy :: (a -> a -> Bool) -> Set a -> Set a - nubSetBy f (Set xs) = Set $ nubBy f xs
+ src/Math/PureSet.hs view
@@ -0,0 +1,138 @@+{-| Module : WeakSets +Description : Pure sets are nested sets which only contain other sets all the way down. They allow to explore basic set theory. +Copyright : Guillaume Sabbagh 2022 +License : GPL-3 +Maintainer : guillaumesabbagh@protonmail.com +Stability : experimental +Portability : portable + +Pure sets are nested sets which only contain other sets all the way down. They allow to explore basic set theory. + +Every mathematical object is a set, usual constructions such as Von Neumann numbers and Kuratowski pairs are implemented. + +It is a tree where the order of the branches does not matter. + +Functions with the same name as homogeneous set functions are suffixed with the letter 'P' for pure to avoid name collision. +-} + +module Math.PureSet +( + -- * `PureSet` datatype + PureSet(..), + pureSet, + -- * Mathematical constructions using sets + emptySet, + singleton, + pair, + cartesianProduct, + numberToSet, + (||||), + (&&&&), + isInP, + isIncludedInP, + card, + powerSetP, + -- * Formatting functions + prettify, + formatPureSet, +) +where + import Data.WeakSet (Set) + import Data.WeakSet.Safe + import qualified Data.WeakSet as S + import Data.List (intersect, nub, intercalate, subsequences) + import Data.Maybe (fromJust, catMaybes) + + -- | A `PureSet` is a `Set` of other pure sets. + data PureSet = PureSet (Set PureSet) deriving (Eq) + + instance Show PureSet where + show (PureSet xs) = "(pureSet "++ show (setToList xs) ++")" + + -- | Construct a `PureSet` from a list of pure sets. + pureSet :: [PureSet] -> PureSet + pureSet = (PureSet).set + + -- | Peel a `PureSet` into a `Set`. + pureSetToSet :: PureSet -> Set PureSet + pureSetToSet (PureSet xs) = xs + + -- | Construct the empty set. + emptySet :: PureSet + emptySet = pureSet [] + + -- | Construct the singleton containing a given set. + singleton :: PureSet -> PureSet + singleton x = pureSet $ [x] + + -- | Construct an ordered pair from two sets according to Kuratowski's definition of a tuple. + pair :: PureSet -> PureSet -> PureSet + pair x y = PureSet $ set [singleton x, pureSet $ [x,y]] + + -- | Construct the cartesian product of two sets. + cartesianProduct :: PureSet -> PureSet -> PureSet + cartesianProduct (PureSet xs) (PureSet ys) = pureSet $ [pair x y | x <- setToList xs, y <- setToList ys] + + -- | Union of two pure sets. + (||||) :: PureSet -> PureSet -> PureSet + (||||) (PureSet xs) (PureSet ys) = PureSet $ xs ||| ys + + -- | Intersection of two pure sets. + (&&&&) :: PureSet -> PureSet -> PureSet + (&&&&) (PureSet xs) (PureSet ys) = PureSet $ xs |&| ys + + -- | Difference of two pure sets. + (\\\\) :: PureSet -> PureSet -> PureSet + (\\\\) (PureSet xs) (PureSet ys) = PureSet $ xs |-| ys + + -- | Transform a number into its Von Neumann construction + numberToSet :: (Num a, Eq a) => a -> PureSet + numberToSet 0 = emptySet + numberToSet n = (numberToSet (n-1)) |||| (singleton (numberToSet (n-1))) + + -- | Return wether a pure set is in another one. + isInP :: PureSet -> PureSet -> Bool + isInP x (PureSet xs) = x `isIn` xs + + -- | Return wether a pure set is included in another one. + isIncludedInP :: PureSet -> PureSet -> Bool + isIncludedInP (PureSet xs) (PureSet ys) = xs `isIncludedIn` ys + + -- | Return the size of a pure set. + card :: PureSet -> Int + card (PureSet xs) = cardinal xs + + -- | Return the set of subsets of a given set. + powerSetP :: PureSet -> PureSet + powerSetP (PureSet xs) = PureSet $ PureSet <$> S.powerSet xs + + -- | Prettiffy a pure set according to usual mathematical notation. + prettify :: PureSet -> String + prettify (PureSet xs) + | cardinal xs == 0 = "{}" + | otherwise = "{" ++ (intercalate ", " $ prettify <$> setToList xs) ++ "}" + + -- | Format pure sets such that if numbers are recognized, they are transformed into integer and if pairs are recognized, they are transformed into pairs. + formatPureSet :: PureSet -> String + formatPureSet x + | (not.null) $ toNumber x = show.fromJust $ toNumber x + | (not.null) $ toPair x = fromJust.toPair $ x + | otherwise = "{"++intercalate "," (formatPureSet <$> (setToList.pureSetToSet $ x))++"}" + where + toNumber s@(PureSet xs) + | s == emptySet = Just 0 + | otherwise = let + numbers = setToList $ toNumber <$> xs + anyMissing = null $ foldr1 (>>) numbers + maxNb = maximum $ catMaybes numbers + in + if (not anyMissing) && (set (Just <$> [0..maxNb])) == (set numbers) then Just (maxNb + 1) else Nothing + toPair (PureSet xs) + | cardinal xs == 2 = + case () of + () | ((card $ (setToList xs) !! 0) == 1 && (card $ (setToList xs) !! 1) == 2) && ((setToList xs) !! 0) `isInP` ((setToList xs) !! 1) -> Just $ "(" ++ (formatPureSet.head.setToList.pureSetToSet $ ((setToList xs) !! 0)) ++ "," ++ (formatPureSet.head.setToList.pureSetToSet $ (((setToList xs) !! 1) \\\\ ((setToList xs) !! 0))) ++ ")" + | ((card $ (setToList xs) !! 1) == 1 && (card $ (setToList xs) !! 0) == 2) && ((setToList xs) !! 1) `isInP` ((setToList xs) !! 0) -> Just $ "(" ++ (formatPureSet.head.setToList.pureSetToSet $ ((setToList xs) !! 1)) ++ "," ++ (formatPureSet.head.setToList.pureSetToSet $ (((setToList xs) !! 0) \\\\ ((setToList xs) !! 1))) ++ ")" + | otherwise -> Nothing + | otherwise = Nothing + +
− src/Math/WeakSets/PureSet.hs
@@ -1,136 +0,0 @@-{-| Module : WeakSets -Description : Pure sets are nested sets which only contain other sets all the way down. They allow to explore basic set theory. -Copyright : Guillaume Sabbagh 2022 -License : GPL-3 -Maintainer : guillaumesabbagh@protonmail.com -Stability : experimental -Portability : portable - -Pure sets are nested sets which only contain other sets all the way down. They allow to explore basic set theory. - -Every mathematical object is a set, usual constructions such as Von Neumann numbers and Kuratowski pairs are implemented. - -It is a tree where the order of the branches does not matter. - -Functions with the same name as homogeneous set functions are suffixed with the letter 'P' for pure to avoid name collision. --} - -module Math.WeakSets.PureSet -( - -- * `PureSet` datatype - PureSet(..), - pureSet, - -- * Mathematical constructions using sets - emptySet, - singleton, - pair, - cartesianProduct, - numberToSet, - (||||), - (&&&&), - isInP, - isIncludedInP, - card, - powerSetP, - -- * Formatting functions - prettify, - formatPureSet, -) -where - import Data.WeakSets.HomogeneousSet - import Data.List (intersect, nub, intercalate, subsequences) - import Data.Maybe (fromJust, catMaybes) - - -- | A `PureSet` is a `Set` of other pure sets. - data PureSet = PureSet (Set PureSet) deriving (Eq) - - instance Show PureSet where - show (PureSet xs) = "(pureSet "++ show (setToList xs) ++")" - - -- | Construct a `PureSet` from a list of pure sets. - pureSet :: [PureSet] -> PureSet - pureSet = (PureSet).set - - -- | Peel a `PureSet` into a `Set`. - pureSetToSet :: PureSet -> Set PureSet - pureSetToSet (PureSet xs) = xs - - -- | Construct the empty set. - emptySet :: PureSet - emptySet = pureSet [] - - -- | Construct the singleton containing a given set. - singleton :: PureSet -> PureSet - singleton x = pureSet $ [x] - - -- | Construct an ordered pair from two sets according to Kuratowski's definition of a tuple. - pair :: PureSet -> PureSet -> PureSet - pair x y = PureSet $ set [singleton x, pureSet $ [x,y]] - - -- | Construct the cartesian product of two sets. - cartesianProduct :: PureSet -> PureSet -> PureSet - cartesianProduct (PureSet xs) (PureSet ys) = pureSet $ [pair x y | x <- setToList xs, y <- setToList ys] - - -- | Union of two pure sets. - (||||) :: PureSet -> PureSet -> PureSet - (||||) (PureSet xs) (PureSet ys) = PureSet $ xs ||| ys - - -- | Intersection of two pure sets. - (&&&&) :: PureSet -> PureSet -> PureSet - (&&&&) (PureSet xs) (PureSet ys) = PureSet $ xs |&| ys - - -- | Difference of two pure sets. - (\\\\) :: PureSet -> PureSet -> PureSet - (\\\\) (PureSet xs) (PureSet ys) = PureSet $ xs |-| ys - - -- | Transform a number into its Von Neumann construction - numberToSet :: (Num a, Eq a) => a -> PureSet - numberToSet 0 = emptySet - numberToSet n = (numberToSet (n-1)) |||| (singleton (numberToSet (n-1))) - - -- | Return wether a pure set is in another one. - isInP :: PureSet -> PureSet -> Bool - isInP x (PureSet xs) = x `isIn` xs - - -- | Return wether a pure set is included in another one. - isIncludedInP :: PureSet -> PureSet -> Bool - isIncludedInP (PureSet xs) (PureSet ys) = xs `isIncludedIn` ys - - -- | Return the size of a pure set. - card :: PureSet -> Int - card (PureSet xs) = cardinal xs - - -- | Return the set of subsets of a given set. - powerSetP :: PureSet -> PureSet - powerSetP (PureSet xs) = PureSet $ PureSet <$> powerSet xs - - -- | Prettiffy a pure set according to usual mathematical notation. - prettify :: PureSet -> String - prettify (PureSet xs) - | cardinal xs == 0 = "{}" - | otherwise = "{" ++ (intercalate ", " $ prettify <$> setToList xs) ++ "}" - - -- | Format pure sets such that if numbers are recognized, they are transformed into integer and if pairs are recognized, they are transformed into pairs. - formatPureSet :: PureSet -> String - formatPureSet x - | (not.null) $ toNumber x = show.fromJust $ toNumber x - | (not.null) $ toPair x = fromJust.toPair $ x - | otherwise = "{"++intercalate "," (formatPureSet <$> (setToList.pureSetToSet $ x))++"}" - where - toNumber s@(PureSet xs) - | s == emptySet = Just 0 - | otherwise = let - numbers = setToList $ toNumber <$> xs - anyMissing = null $ foldr1 (>>) numbers - maxNb = maximum $ catMaybes numbers - in - if (not anyMissing) && (set (Just <$> [0..maxNb])) == (set numbers) then Just (maxNb + 1) else Nothing - toPair (PureSet xs) - | cardinal xs == 2 = - case () of - () | ((card $ (setToList xs) !! 0) == 1 && (card $ (setToList xs) !! 1) == 2) && ((setToList xs) !! 0) `isInP` ((setToList xs) !! 1) -> Just $ "(" ++ (formatPureSet.head.setToList.pureSetToSet $ ((setToList xs) !! 0)) ++ "," ++ (formatPureSet.head.setToList.pureSetToSet $ (((setToList xs) !! 1) \\\\ ((setToList xs) !! 0))) ++ ")" - | ((card $ (setToList xs) !! 1) == 1 && (card $ (setToList xs) !! 0) == 2) && ((setToList xs) !! 1) `isInP` ((setToList xs) !! 0) -> Just $ "(" ++ (formatPureSet.head.setToList.pureSetToSet $ ((setToList xs) !! 1)) ++ "," ++ (formatPureSet.head.setToList.pureSetToSet $ (((setToList xs) !! 0) \\\\ ((setToList xs) !! 1))) ++ ")" - | otherwise -> Nothing - | otherwise = Nothing - -
test/AllTests.hs view
@@ -1,12 +1,12 @@ module Main (main) where - import qualified TestHomogeneousSet as HSET - import qualified TestHomogeneousFunction as HFUNCT + import qualified TestWeakSet as WSET + import qualified TestWeakMap as WMAP import qualified TestPureSet as PSET main :: IO () main = do putStrLn "Beginning of the test." - HSET.main - HFUNCT.main + WSET.main + WMAP.main PSET.main putStrLn "End of the tests."
− test/TestHomogeneousFunction.hs
@@ -1,30 +0,0 @@-module TestHomogeneousFunction where - import Data.WeakSets.HomogeneousSet - import Data.WeakSets.HomogeneousFunction - - -- | Tests all functions related to homogeneous sets. - main :: IO () - main = do - putStrLn "Beginning of TestHomogeneousSet" - let s1 = set [1,2,3] - let s2 = set [3,4,5] - let f = function $ zip (setToList s1) (setToList s2) - let g = function $ zip (setToList s2) (setToList s1) - putStrLn $ show $ f - putStrLn $ show $ g - putStrLn $ show $ functionToSet $ f - putStrLn $ show $ domain $ f - putStrLn $ show $ image $ f - putStrLn $ show $ f |?| 1 - putStrLn $ show $ f |!| 1 - putStrLn $ show $ f |.| g - putStrLn $ show $ g |.| f - putStrLn $ show $ memorizeFunction (*3) (set [1..10]) - putStrLn $ show $ idFromSet (set [1..10]) - putStrLn $ show $ size (idFromSet (set [1..10])) - putStrLn $ show $ delete 3 (idFromSet (set [1..10])) - putStrLn $ show $ adjust (+1) 3 (idFromSet (set [1..10])) - putStrLn $ show $ adjust (+1) 13 (idFromSet (set [1..10])) - putStrLn $ show $ union (idFromSet (set [1..10])) (idFromSet (set [5..15])) - putStrLn "End of TestHomogeneousSet" -
− test/TestHomogeneousSet.hs
@@ -1,26 +0,0 @@-module TestHomogeneousSet where - import Data.WeakSets.HomogeneousSet - - -- | Tests all functions related to homogeneous sets. - main :: IO () - main = do - putStrLn "Beginning of TestHomogeneousSet" - let s1 = set [1,2,3] - let s2 = set [3,4,5] - putStrLn $ show $ s1 - putStrLn $ show $ setToList s1 - putStrLn $ show $ s2 `isIncludedIn` s1 - putStrLn $ show $ (set [1,2]) `isIncludedIn` s1 - putStrLn $ show $ cardinal s1 - putStrLn $ show $ 3 `isIn` s1 - putStrLn $ show $ (+1) <$> s1 - putStrLn $ show $ (+) <$> s1 <*> s2 - putStrLn $ show $ s1 |&| s2 - putStrLn $ show $ s1 ||| s2 - putStrLn $ show $ s1 |*| s2 - putStrLn $ show $ s1 |+| s2 - putStrLn $ show $ s1 |-| s2 - putStrLn $ show $ s1 |^| 3 - putStrLn $ show $ powerSet s1 - putStrLn "End of TestHomogeneousSet" -
test/TestPureSet.hs view
@@ -1,6 +1,5 @@ module TestPureSet where - import Data.WeakSets.HomogeneousSet - import Math.WeakSets.PureSet + import Math.PureSet import Data.List (intercalate) -- | Tests all functions related to pure sets.
+ test/TestWeakMap.hs view
@@ -0,0 +1,32 @@+module TestWeakMap where + import Data.WeakMap.Safe + import qualified Data.WeakMap as M + import Data.WeakSet.Safe + import qualified Data.WeakSet as S + + -- | Tests all functions related to weak maps. + main :: IO () + main = do + putStrLn "Beginning of TestWeakMap" + let s1 = set [1,2,3] + let s2 = set [3,4,5] + let f = weakMap $ zip (setToList s1) (setToList s2) + let g = weakMap $ zip (setToList s2) (setToList s1) + putStrLn $ show $ f + putStrLn $ show $ g + putStrLn $ show $ M.mapToSet $ f + putStrLn $ show $ domain $ f + putStrLn $ show $ image $ f + putStrLn $ show $ f |?| 1 + putStrLn $ show $ f |!| 1 + putStrLn $ show $ f |.| g + putStrLn $ show $ g |.| f + putStrLn $ show $ memorizeFunction (*3) (set [1..10]) + putStrLn $ show $ idFromSet (set [1..10]) + putStrLn $ show $ M.size (idFromSet (set [1..10])) + putStrLn $ show $ M.delete 3 (idFromSet (set [1..10])) + putStrLn $ show $ M.adjust (+1) 3 (idFromSet (set [1..10])) + putStrLn $ show $ M.adjust (+1) 13 (idFromSet (set [1..10])) + putStrLn $ show $ M.union (idFromSet (set [1..10])) (idFromSet (set [5..15])) + putStrLn "End of TestWeakMap" +
+ test/TestWeakSet.hs view
@@ -0,0 +1,26 @@+module TestWeakSet where + import Data.WeakSet + + -- | Tests all functions related to homogeneous sets. + main :: IO () + main = do + putStrLn "Beginning of TestWeakSet" + let s1 = set [1,2,3] + let s2 = set [3,4,5] + putStrLn $ show $ s1 + putStrLn $ show $ setToList s1 + putStrLn $ show $ s2 `isIncludedIn` s1 + putStrLn $ show $ (set [1,2]) `isIncludedIn` s1 + putStrLn $ show $ cardinal s1 + putStrLn $ show $ 3 `isIn` s1 + putStrLn $ show $ (+1) <$> s1 + putStrLn $ show $ (+) <$> s1 <*> s2 + putStrLn $ show $ s1 |&| s2 + putStrLn $ show $ s1 ||| s2 + putStrLn $ show $ s1 |*| s2 + putStrLn $ show $ s1 |+| s2 + putStrLn $ show $ s1 |-| s2 + putStrLn $ show $ s1 |^| 3 + putStrLn $ show $ powerSet s1 + putStrLn "End of TestWeakSet" +