Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
This module implements a way of tracking the contents of a
HashSet
at the type level, and provides utilities for
manipulating such sets.
The contents of a set are associated with a type parameter, e.g. s
, so that
whenever you see the same type parameter, you know you are working with the
same set. The type s
itself has no internal structure, rather it is merely
a skolem type variable (rank-2 polymorphism runST
trick)
introduced by Data.Reflection.
Warning
This module together with Data.HashSet rely on Eq
and Hashable
instances being lawful: that ==
is an equivalence relation, and that
hashWithSalt
is defined on the quotient by this equivalence
relation; at least for the subset of values that are actually encountered at
runtime. If this assumption is violated, this module may not be able to
uphold its invariants and may throw errors. In particular beware of NaN in
Float
and Double
, and, if using hashable < 1.3
, beware of 0
and -0
.
Synopsis
- type KnownHashSet s a = Reifies s (HashSet a)
- type HashSet s a = Dict (KnownHashSet s a)
- data InSet (f :: Flavor) (s :: Type) = InSet
- data Flavor = Hashed
- type Element s = Refined (InSet 'Hashed s)
- revealPredicate :: forall s a. (Typeable a, Hashable a, KnownHashSet s a) => Dict (Predicate (InSet 'Hashed s) a)
- data SomeHashSet a where
- SomeHashSet :: forall s a. KnownHashSet s a => Proxy# s -> SomeHashSet a
- withHashSet :: forall a r. SomeHashSet a -> (forall s. KnownHashSet s a => Proxy s -> r) -> r
- data SomeHashSetWith p a where
- SomeHashSetWith :: forall s a p. KnownHashSet s a => !(p s) -> SomeHashSetWith p a
- withHashSetWith :: forall a r p. SomeHashSetWith p a -> (forall s. KnownHashSet s a => p s -> r) -> r
- data Some2HashSetWith p a where
- Some2HashSetWith :: forall s t a p. (KnownHashSet s a, KnownHashSet t a) => !(p s t) -> Some2HashSetWith p a
- with2HashSetWith :: forall a r p. Some2HashSetWith p a -> (forall s t. (KnownHashSet s a, KnownHashSet t a) => p s t -> r) -> r
- type (:->) p q = forall x. Refined p x -> Refined q x
- newtype SupersetProof f s r = SupersetProof (InSet f r :-> InSet f s)
- newtype EmptyProof f r = EmptyProof (forall s. InSet f r :-> InSet f s)
- empty :: forall a. SomeHashSetWith (EmptyProof 'Hashed) a
- singleton :: forall a. Hashable a => a -> SomeHashSetWith (SingletonProof 'Hashed a) a
- newtype SingletonProof f a r = SingletonProof (Refined (InSet f r) a)
- fromHashSet :: forall a. HashSet a -> SomeHashSet a
- fromTraversable :: forall t a. (Traversable t, Hashable a) => t a -> SomeHashSetWith (FromTraversableProof 'Hashed t a) a
- newtype FromTraversableProof f (t :: Type -> Type) a r = FromTraversableProof (t (Refined (InSet f r) a))
- insert :: forall s a. (Hashable a, KnownHashSet s a) => a -> SomeHashSetWith (InsertProof 'Hashed a s) a
- data InsertProof f a s r = InsertProof (Refined (InSet f r) a) (InSet f s :-> InSet f r)
- delete :: forall s a. (Hashable a, KnownHashSet s a) => a -> SomeHashSetWith (SupersetProof 'Hashed s) a
- member :: forall s a. (Hashable a, KnownHashSet s a) => a -> Maybe (Element s a)
- null :: forall s a. KnownHashSet s a => Maybe (EmptyProof 'Hashed s)
- isSubsetOf :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => Maybe (SubsetProof 'Hashed s t)
- newtype SubsetProof f s r = SubsetProof (InSet f s :-> InSet f r)
- disjoint :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => Maybe (DisjointProof 'Hashed s t)
- newtype DisjointProof f s r = DisjointProof (forall t. (InSet f t :-> InSet f s) -> (InSet f t :-> InSet f r) -> forall u. InSet f t :-> InSet f u)
- union :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => SomeHashSetWith (UnionProof 'Hashed s t) a
- data UnionProof f s t r = UnionProof ((InSet f s || InSet f t) :-> InSet f r) (forall u. (InSet f s :-> InSet f u) -> (InSet f t :-> InSet f u) -> InSet f r :-> InSet f u)
- difference :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => SomeHashSetWith (DifferenceProof 'Hashed s t) a
- data DifferenceProof f s t r = DifferenceProof (InSet f r :-> InSet f s) (forall u. (InSet f u :-> InSet f r) -> (InSet f u :-> InSet f t) -> forall v. InSet f u :-> InSet f v) (InSet f s :-> (InSet f t || InSet f r))
- intersection :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => SomeHashSetWith (IntersectionProof 'Hashed s t) a
- data IntersectionProof f s t r = IntersectionProof (InSet f r :-> (InSet f s && InSet f t)) (forall u. (InSet f u :-> InSet f s) -> (InSet f u :-> InSet f t) -> InSet f u :-> InSet f r)
- filter :: forall s a. KnownHashSet s a => (Element s a -> Bool) -> SomeHashSetWith (SupersetProof 'Hashed s) a
- partition :: forall s a. KnownHashSet s a => (Element s a -> Bool) -> Some2HashSetWith (PartitionProof 'Hashed s a) a
- data PartitionProof f s a r q = PartitionProof (Refined (InSet f s) a -> Either (Refined (InSet f r) a) (Refined (InSet f q) a)) ((InSet f r || InSet f q) :-> InSet f s) (forall t. (InSet f r :-> InSet f t) -> (InSet f q :-> InSet f t) -> InSet f s :-> InSet f t) (forall t. (InSet f t :-> InSet f r) -> (InSet f t :-> InSet f q) -> forall u. InSet f t :-> InSet f u)
- map :: forall s a b. (Hashable b, KnownHashSet s a) => (Element s a -> b) -> SomeHashSetWith (MapProof 'Hashed s a b) b
- data MapProof f s a b r = MapProof (Refined (InSet f s) a -> Refined (InSet f r) b) (Refined (InSet f r) b -> Refined (InSet f s) a)
- foldMap :: forall s a m. (KnownHashSet s a, Monoid m) => (Element s a -> m) -> m
- foldr :: forall s a b. KnownHashSet s a => (Element s a -> b -> b) -> b -> b
- foldl :: forall s a b. KnownHashSet s a => (b -> Element s a -> b) -> b -> b
- foldr' :: forall s a b. KnownHashSet s a => (Element s a -> b -> b) -> b -> b
- foldl' :: forall s a b. KnownHashSet s a => (b -> Element s a -> b) -> b -> b
- toList :: forall s a. KnownHashSet s a => [Element s a]
- asSet :: forall s a. (Ord a, KnownHashSet s a) => Set s a
- asIntSet :: forall s. KnownHashSet s Int => IntSet s
- castElement :: forall s t a. (forall x. Element s x -> Element t x) -> (forall x. Element t x -> Element s x) -> Coercion (Element s a) (Element t a)
- cast :: forall s t a. (forall x. Coercion (Element s x) (Element t x)) -> Coercion (HashSet s a) (HashSet t a)
- castFlavor :: forall (f :: Flavor) (g :: Flavor) s a. Coercion (Refined (InSet f s) a) (Refined (InSet g s) a)
Set type
type KnownHashSet s a = Reifies s (HashSet a) Source #
type HashSet s a = Dict (KnownHashSet s a) Source #
A HashSet
whose contents are tracked by the type parameter
s
. This is a "singleton": for a given s
there's only one value of this
type.
Since this is just a Dict
, you can freely convert between the value
(HashSet
) and the constraint (KnownHashSet
). This library prefers to use
the constraint.
Refinement type
data InSet (f :: Flavor) (s :: Type) Source #
A predicate for use with Refined, verifying that a value is an element of
the set s
.
Instances
(Hashable a, Typeable s, KnownHashSet s a) => Predicate (InSet 'Hashed s :: Type) a Source # | See |
Defined in Data.Container.Refined.Proofs | |
(a ~ Int, Typeable s, KnownIntSet s) => Predicate (InSet 'Int s :: Type) a Source # | See |
Defined in Data.Container.Refined.Proofs | |
(Ord a, Typeable s, KnownSet s a) => Predicate (InSet 'Regular s :: Type) a Source # | See |
Defined in Data.Container.Refined.Proofs | |
FoldableWithIndex (Key s) (IntMap s) Source # | |
Defined in Data.IntMap.Common.Refined ifoldMap :: Monoid m => (Key s -> a -> m) -> IntMap s a -> m # ifoldMap' :: Monoid m => (Key s -> a -> m) -> IntMap s a -> m # ifoldr :: (Key s -> a -> b -> b) -> b -> IntMap s a -> b # ifoldl :: (Key s -> b -> a -> b) -> b -> IntMap s a -> b # | |
FunctorWithIndex (Key s) (IntMap s) Source # | |
TraversableWithIndex (Key s) (IntMap s) Source # | |
Defined in Data.IntMap.Common.Refined | |
KnownIntSet s => MonadReader (Key s) (IntMap s) Source # | Similar to the instance for functions. See also
|
FoldableWithIndex (Key s k) (HashMap s k) Source # | |
Defined in Data.HashMap.Common.Refined ifoldMap :: Monoid m => (Key s k -> a -> m) -> HashMap s k a -> m # ifoldMap' :: Monoid m => (Key s k -> a -> m) -> HashMap s k a -> m # ifoldr :: (Key s k -> a -> b -> b) -> b -> HashMap s k a -> b # ifoldl :: (Key s k -> b -> a -> b) -> b -> HashMap s k a -> b # ifoldr' :: (Key s k -> a -> b -> b) -> b -> HashMap s k a -> b # ifoldl' :: (Key s k -> b -> a -> b) -> b -> HashMap s k a -> b # | |
FoldableWithIndex (Key s k) (Map s k) Source # | |
Defined in Data.Map.Common.Refined ifoldMap :: Monoid m => (Key s k -> a -> m) -> Map s k a -> m # ifoldMap' :: Monoid m => (Key s k -> a -> m) -> Map s k a -> m # ifoldr :: (Key s k -> a -> b -> b) -> b -> Map s k a -> b # ifoldl :: (Key s k -> b -> a -> b) -> b -> Map s k a -> b # ifoldr' :: (Key s k -> a -> b -> b) -> b -> Map s k a -> b # ifoldl' :: (Key s k -> b -> a -> b) -> b -> Map s k a -> b # | |
FunctorWithIndex (Key s k) (HashMap s k) Source # | |
FunctorWithIndex (Key s k) (Map s k) Source # | |
TraversableWithIndex (Key s k) (HashMap s k) Source # | |
Defined in Data.HashMap.Common.Refined | |
TraversableWithIndex (Key s k) (Map s k) Source # | |
Defined in Data.Map.Common.Refined | |
(Hashable k, KnownHashSet s k) => MonadReader (Key s k) (HashMap s k) Source # | Similar to the instance for functions. See also
|
(Ord k, KnownSet s k) => MonadReader (Key s k) (Map s k) Source # | Similar to the instance for functions. See also
|
Disambiguate the choice of implementation for sets and maps.
type Element s = Refined (InSet 'Hashed s) Source #
is a value of type Element
s aa
that has been verified to be an
element of s
.
Thus,
is a "refinement" type of Element
s aa
, and this library
integrates with an implementation of refimenement types in Refined, so
the machinery from there can be used to manipulate Element
s (however see
revealPredicate
).
The underlying a
value can be obtained with unrefine
. An a
can be
validated into an
with Element
s amember
.
revealPredicate :: forall s a. (Typeable a, Hashable a, KnownHashSet s a) => Dict (Predicate (InSet 'Hashed s) a) Source #
To use Refined machinery that uses the Predicate
typeclass you will
need to pattern match on this Dict
.
The reason is that in the default fast implementation of reflection, we
don't have
, which Refined wants for pretty-printing
exceptions. We can provide Typeable
s
, but at the cost of using the
slow implementation of reflection.Typeable
s
Existentials and common proofs
data SomeHashSet a where Source #
An existential wrapper for an as-yet-unknown set. Pattern maching on it gives you a way to refer to the set, e.g.
casefromHashSet
... ofSomeHashSet
@s _ -> doSomethingWith @s casefromHashSet
... ofSomeHashSet
(_ ::Proxy#
s) -> doSomethingWith @s
SomeHashSet :: forall s a. KnownHashSet s a => Proxy# s -> SomeHashSet a |
withHashSet :: forall a r. SomeHashSet a -> (forall s. KnownHashSet s a => Proxy s -> r) -> r Source #
Apply an unknown set to a continuation that can accept any set. This gives
you a way to refer to the set (the parameter s
), e.g.:
withHashSet
(fromHashSet
...) $ (_ ::Proxy
s) -> doSomethingWith @s
data SomeHashSetWith p a where Source #
An existential wrapper for an as-yet-unknown set, together with a proof of
some fact p
about the set. Pattern matching on it gives you a way to refer
to the set (the parameter s
). Most functions will return a set in this way,
together with a proof that somehow relates the set to the function's inputs.
SomeHashSetWith :: forall s a p. KnownHashSet s a => !(p s) -> SomeHashSetWith p a |
withHashSetWith :: forall a r p. SomeHashSetWith p a -> (forall s. KnownHashSet s a => p s -> r) -> r Source #
Apply an unknown set with proof to a continuation that can accept any set
satisfying the proof. This gives you a way to refer to the set (the parameter
s
).
data Some2HashSetWith p a where Source #
An existential wrapper for an as-yet-unknown pair of sets, together with
a proof of some fact p
relating them.
Some2HashSetWith :: forall s t a p. (KnownHashSet s a, KnownHashSet t a) => !(p s t) -> Some2HashSetWith p a |
with2HashSetWith :: forall a r p. Some2HashSetWith p a -> (forall s t. (KnownHashSet s a, KnownHashSet t a) => p s t -> r) -> r Source #
Apply a pair of unknown sets with proof to a continuation that can accept
any pair of sets satisfying the proof. This gives you a way to refer to the
sets (the parameters s
and t
).
newtype SupersetProof f s r Source #
Proof that s
is a superset of the set r
.
SupersetProof (InSet f r :-> InSet f s) | \(r \subseteq s\) |
newtype EmptyProof f r Source #
Proof that the set r
is empty.
EmptyProof (forall s. InSet f r :-> InSet f s) | \(\forall s, r \subseteq s\), which is equivalent to \(r \subseteq \varnothing\) |
Construction
empty :: forall a. SomeHashSetWith (EmptyProof 'Hashed) a Source #
An empty set.
singleton :: forall a. Hashable a => a -> SomeHashSetWith (SingletonProof 'Hashed a) a Source #
Create a set with a single element.
newtype SingletonProof f a r Source #
Proof that r
contains an element of type a
.
SingletonProof (Refined (InSet f r) a) | The element that is guaranteed to be in |
fromHashSet :: forall a. HashSet a -> SomeHashSet a Source #
Construct a set from a regular HashSet
.
fromTraversable :: forall t a. (Traversable t, Hashable a) => t a -> SomeHashSetWith (FromTraversableProof 'Hashed t a) a Source #
Create a set from the elements of an arbitrary traversable.
newtype FromTraversableProof f (t :: Type -> Type) a r Source #
Proof that elements of t a
are contained in r
.
FromTraversableProof (t (Refined (InSet f r) a)) | The original traversable, with all elements refined with a guarantee of
being in |
Insertion
insert :: forall s a. (Hashable a, KnownHashSet s a) => a -> SomeHashSetWith (InsertProof 'Hashed a s) a Source #
Insert an element in a set.
data InsertProof f a s r Source #
Proof that r
is s
with a
inserted.
Deletion
delete :: forall s a. (Hashable a, KnownHashSet s a) => a -> SomeHashSetWith (SupersetProof 'Hashed s) a Source #
Delete an element from a set.
Query
member :: forall s a. (Hashable a, KnownHashSet s a) => a -> Maybe (Element s a) Source #
If an element is in the set, return the proof that it is.
null :: forall s a. KnownHashSet s a => Maybe (EmptyProof 'Hashed s) Source #
If the set is empty, return the proof that it is.
isSubsetOf :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => Maybe (SubsetProof 'Hashed s t) Source #
If s
is a subset of t
(or is equal to), return a proof of that.
newtype SubsetProof f s r Source #
Proof that s
is a subset of the set r
.
SubsetProof (InSet f s :-> InSet f r) | \(s \subseteq r\) |
disjoint :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => Maybe (DisjointProof 'Hashed s t) Source #
If s
and t
are disjoint (i.e. their intersection is empty), return a
proof of that.
newtype DisjointProof f s r Source #
Proof that s
and r
are disjoint.
Combine
union :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => SomeHashSetWith (UnionProof 'Hashed s t) a Source #
The union of two sets.
data UnionProof f s t r Source #
Proof that unioning s
and t
gives r
.
difference :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => SomeHashSetWith (DifferenceProof 'Hashed s t) a Source #
HashSet with elements of s
that are not in t
.
data DifferenceProof f s t r Source #
Proof that if from s
you subtract t
, then you get r
.
DifferenceProof | |
|
intersection :: forall s t a. (Hashable a, KnownHashSet s a, KnownHashSet t a) => SomeHashSetWith (IntersectionProof 'Hashed s t) a Source #
Intersection of two sets.
data IntersectionProof f s t r Source #
Proof that intersecting s
and t
gives r
.
Filter
filter :: forall s a. KnownHashSet s a => (Element s a -> Bool) -> SomeHashSetWith (SupersetProof 'Hashed s) a Source #
Return a subset of elements that satisfy the given predicate.
partition :: forall s a. KnownHashSet s a => (Element s a -> Bool) -> Some2HashSetWith (PartitionProof 'Hashed s a) a Source #
Partition a set into two disjoint subsets: those that satisfy the predicate, and those that don't.
data PartitionProof f s a r q Source #
Proof that s
is the union of disjoint subsets r
and q
, together with
a procedure that decides which of the two an element belongs to.
PartitionProof | |
|
Map
map :: forall s a b. (Hashable b, KnownHashSet s a) => (Element s a -> b) -> SomeHashSetWith (MapProof 'Hashed s a b) b Source #
Apply the given function to each element of the set and collect the results. Note that the resulting set can be smaller.
data MapProof f s a b r Source #
Proof that r
is the direct image of s
under some mapping f :: a -> b
.
Folds
foldMap :: forall s a m. (KnownHashSet s a, Monoid m) => (Element s a -> m) -> m Source #
Map each element of s
into a monoid (with proof that it was an element),
and combine the results using <>
.
foldr :: forall s a b. KnownHashSet s a => (Element s a -> b -> b) -> b -> b Source #
Right associative fold with a lazy accumulator.
foldl :: forall s a b. KnownHashSet s a => (b -> Element s a -> b) -> b -> b Source #
Left associative fold with a lazy accumulator.
foldr' :: forall s a b. KnownHashSet s a => (Element s a -> b -> b) -> b -> b Source #
Right associative fold with a strict accumulator.
foldl' :: forall s a b. KnownHashSet s a => (b -> Element s a -> b) -> b -> b Source #
Left associative fold with a strict accumulator.
Conversion
toList :: forall s a. KnownHashSet s a => [Element s a] Source #
List of elements in the set.
asSet :: forall s a. (Ord a, KnownHashSet s a) => Set s a Source #
Convert an IntSet
into a Set
, retaining its set of elements, which can
be converted with castFlavor
.
asIntSet :: forall s. KnownHashSet s Int => IntSet s Source #
Convert an IntSet
into a HashSet
, retaining its set of elements, which
can be converted with castFlavor
.
Casts
castElement :: forall s t a. (forall x. Element s x -> Element t x) -> (forall x. Element t x -> Element s x) -> Coercion (Element s a) (Element t a) Source #
If elements of s
can be weakened to elements of t
and vice versa, then
s
and t
actually stand for the same set and
can be safely
interconverted with Element
s
.Element
t
The requirement that the weakenings are natural transformations ensures that
they don't actually alter the elements. To build these you can compose
:->
's from proofs returned by functions in this module, or Refined
functions like andLeft
or leftOr
.
cast :: forall s t a. (forall x. Coercion (Element s x) (Element t x)) -> Coercion (HashSet s a) (HashSet t a) Source #
If elements can be interconverted (e.g. as proved by castElement
), then
the sets can be interconverted too. For example we can establish that the
intersection of a set with itself is interconvertible with that set:
castIntersection ::IntersectionProof
'Hashed
s s r ->Coercion
(HashSet
r a) (HashSet
s a) castIntersection (IntersectionProof
p1 p2) =cast
$castElement
(andLeft
. p1) (p2id
id
)