=begin pod

=TITLE Sets, Bags, and Mixes

=SUBTITLE Unordered collections of unique and weighted objects in Perl 6

Often you want to collect objects in a container but you do not care
about the order of these objects. For such cases, Perl 6 provides the
I<unordered> collection types L<B<C<Set>>|Set>,
L<B<C<SetHash>>|SetHash>, L<B<C<Bag>>|Bag>, L<B<C<BagHash>>|BagHash>,
L<B<C<Mix>>|Mix>, and L<B<C<MixHash>>|MixHash>. Being unordered, these
containers can be more efficient than L<B<C<Lists>>|List> for looking up
elements or dealing with repeated items.

If you want to get the contained objects (elements) without duplicates
and you only care I<whether> an element is in the collection or not,
you can use a L<B<C<Set>>|Set> or L<B<C<SetHash>>|SetHash>. (If you want
to get rid of duplicates but still preserve order, take a look at the
L<C<unique>|unique> routine for L<B<C<Lists>>|List>.)

=begin comment
=defn  Set or SetHash
Collection of distinct objects
=end comment

If you want to keep track of the number of times each object appeared,
you can use a L<B<C<Bag>>|Bag> or L<B<C<BagHash>>|BagHash>. In these
Baggy containers each element has a weight (an unsigned integer)
indicating the number of times the same object has been included in the
collection. The types L<B<C<Mix>>|Mix> and L<B<C<MixHash>>|MixHash> are
similar, but they also allow fractional weights.

=begin comment
=defn  Bag or BagHash
Collection of distinct objects mapped to integer weights

=defn  Mix or MixHash
Collection of distinct objects mapped to real-number weights
=end comment

=for comment
TODO: Partial type graph showing only QuantHash, Setty, Baggy, Mixy, Set,
      SetHash, Bag, BagHash, Mix, MixHash.

L<B<C<Set>>|Set>, L<B<C<Bag>>|Bag>, and L<B<C<Mix>>|Mix> are I<immutable>
types. Use the mutable variants L<B<C<SetHash>>|SetHash>, L<B<C<BagHash>>|BagHash>,
and L<B<C<MixHash>>|MixHash> if you want to add or remove elements after
the container has been constructed.

The six collection classes C<Set>, C<SetHash>, C<Bag>, C<BagHash>, C<Mix>,
C<MixHash>, all share similar semantics.

For one thing, as far as they are concerned, identical objects refer to the
same element -- where identity is determined using the L<WHICH> methods
(i.e. the same way that the L<===> operator checks identity). For value
types like C<Str>, this means having the same value; for reference types
like C<Array>, it means referring to the same object instance.

Secondly, they provide a Hash-like interface where the actual elements of
the collection (which can be objects of any type) are the 'keys', and the
associated weights are the 'values':

=table
                      value of $a{$b} if $b       value of $a{$b} if $b
    type of $a        is an element               is not an element
    -------------     ----------------------      ---------------------
    Set / SetHash     True                        False
    Bag / BagHash     a positive integer          0
    Mix / MixHash     a non-zero real number      0

=head1 Set/Bag Operators

=comment TODO: Update this after ab5tract's set/bag/mix operator redesign.

There are many infixes devoted to preforming common operations on
L<C<Set>s|Set>, such as unions and set differences. Other operations include
boolean checks, like whether an object is an element of a C<Set>, or whether
one C<Set> is a subset of another C<Set>.

These infixes can be written using the UTF-8 character that represents the
function (like L<C<∈>|∈>, or L<C<∪>|∪>), or they can be written with an
equivalent ASCII version (like L<C<(elem)>|(elem)> or L<C<(|)>|(|)>).

Most of the time, explicitly using C<Set> objects with these infixes is
unnecessary. All of the infix operators will work on any objects of type
L<C<Any>|Any> for its arguments (e.g., L<C<List>s|List>,
L<C<Array>s|Array>, L<C<Mix>es|Mix>, etc.) and coerce them to C<Set>s
where needed.

In some cases, if the type of an argument is a L<Bag>, the infix operator
will behave in a different but analogous way to the way it would behave with
only C<Set> arguments.

=head2 Operators that return C<Bool>

=head3 infix (elem)

    multi sub infix:<(elem)>($a, Any $b --> Bool)
    multi sub infix:<(elem)>($a, Set $b --> Bool)

Returns C<True> if C<$a> is an B<element> of C<$b>.

=head4 infix ∈ (U+2208 ELEMENT OF)

    only sub infix:<<"∈">>($a, $b --> Bool)

Equivalent to L«(elem)».

=head4 infix ∉ (U+2209 NOT AN ELEMENT OF)

    only sub infix:<<"∉">>($a, $b --> Bool)

Equivalent to C<!(elem)>, i.e., returns C<True> if C<$a> is not an element
of C<$b>.

=head3 infix (cont)

    multi sub infix:<(cont)>(Any $a, $b --> Bool)
    multi sub infix:<(cont)>(Set $a, $b --> Bool)

Returns C<True> if C<$a> B<contains> C<$b> as an element.

=head4 infix ∋ (U+220B CONTAINS AS MEMBER)

    only sub infix:<<"∋">>($a, $b --> Bool)

Equivalent to L«(cont)».

=head4 infix ∌ (U+220C DOES NOT CONTAIN AS MEMBER)

    only sub infix:<<"∌">>($a, $b --> Bool)

Equivalent to C<!(cont)>, i.e., returns C<True> if C<$a> does not contain
C<$b>.

=head3 infix (<=)

    multi sub infix:<<(<=)>>(Any $a, Any $b --> Bool)
    multi sub infix:<<(<=)>>(Setty $a, Setty $b --> Bool)

Returns C<True> if C<$a> is a B<subset> or is equal to C<$b>, i.e., if all
the elements of C<$a> are elements of C<$b> and C<$a> is a smaller or equal
sized set than C<$b>.

=head4 infix ⊆ (U+2286 SUBSET OF OR EQUAL TO)

    only sub infix:<<"⊆">>($a, $b --> Bool)

Equivalent to L«(<=)».

=head4 infix ⊈ U+2288 NEITHER A SUBSET OF NOR EQUAL TO

    only sub infix:<<"⊈">>($a, $b --> Bool)

Equivalent to C«!(<=)».

=head3 infix (<)

    multi sub infix:<<(<)>>(Any $a, Any $b --> Bool)
    multi sub infix:<<(<)>>(Setty $a, Setty $b --> Bool)

Returns C<True> if C<$a> is a B<strict subset> of C<$b>, i.e., that all the
elements of C<$a> are elements of C<$b> but C<$a> is a smaller set than
C<$b>.

=head4 infix ⊂ (U+2282 SUBSET OF)

    only sub infix:<<"⊂">>($a, $b --> Bool)

Equivalent to L«(<)».

=head4 infix ⊄ (U+2284 NOT A SUBSET OF)

    only sub infix:<<"⊄">>($a, $b --> Bool)

Equivalent to C«!(<)».

=head3 infix (>=)

    multi sub infix:<<(>=)>>(Any $a, Any $b --> Bool)
    multi sub infix:<<(>=)>>(Setty $a, Setty $b --> Bool)

Like L«(<=)» with reversed arguments. Returns C<True> if C<$a> is a
B<superset> of or equal to C<$b>.

=head4 infix ⊇ (U+2287 SUPERSET OF OR EQUAL TO)

    only sub infix:<<"⊇">>($a, $b --> Bool)

Equivalent to L«(>=)».

=head4 infix ⊉ (U+2289 NEITHER A SUPERSET OF NOR EQUAL TO)

    only sub infix:<<"⊉">>($a, $b --> Bool)

Equivalent to C«!(>=)».

=head3 infix (>)

    multi sub infix:<<(>)>>(Any $a, Any $b --> Bool)
    multi sub infix:<<(>)>>(Setty $a, Setty $b --> Bool)

Like L«(<)» with reversed arguments. Returns C<True> if C<$a> is a
B<strict superset> of C<$b>.

=head4 infix ⊃ (U+2283 SUPERSET OF)

    only sub infix:<<"⊃">>($a, $b --> Bool)

Equivalent to L«(>)».

=head4 infix ⊅ (U+2285 NOT A SUPERSET OF)

    only sub infix:<<"⊅">>($a, $b --> Bool)

Equivalent to C«!(>)».

=head3 infix (<+)

    multi sub infix:<<(<+)>>(Any $a, Any $b --> Bool)
    multi sub infix:<<(<+)>>(Baggy $a, Baggy $b --> Bool)

Returns C<True> if C<$a> is a Baggy B<subset> of C<$b>, i.e., if all the
elements of C<$a> are in C<$b> and each element of C<$b> is weighed at
least as heavily as the element is in C<$a>.

=head4 infix ≼ (U+227C PRECEDES OR EQUAL TO)

    only sub infix:<<"≼">>($a, $b --> Bool)

Equivalent to L«(<+)».

=head3 infix (>+)

    multi sub infix:<<(>+)>>(Baggy $a, Baggy $b --> Bool)
    multi sub infix:<<(>+)>>(Any $a, Any $b --> Bool)

Returns C<True> if C<$a> is a Baggy B<superset> of C<$b>, i.e., if all the
elements of C<$b> are in C<$a> and no element of C<$b> is weighted heavier
than that element is in C<$a>.

=head4 infix ≽ (U+227D SUCCEEDS OR EQUAL TO)

    only sub infix:<<"≽">>($a, $b --> Bool)

Equivalent to L«(+>)».

=head2 Operators that return C<Set> or C<Bag>

=head3 infix (|)

    only sub infix:<(|)>(**@p)

Returns the B<union> of all its arguments. Generally, this creates a new
C<Set> that contains all the elements its arguments contain.

    <a a b c d> (|) <h g f e d c> (|) <i j> === set <a b c d e f g h i j>

If any of its arguments are C<Baggy>, it creates a new C<Bag> that contains
all the elements of the arguments, each weighed by the highest weight that
appeared for that element.

    bag(<a a b c a>) (|) bag(<a a b c c>) === bag(<a a a b c c>)

=head4 infix ∪ (U+222A UNION)

    only sub infix:<<"∪">>(|p)

Equivalent to L«(V<|>)».

=head3 infix (&)

    only sub infix:<(&)>(**@p)

Returns the B<intersection> of all of its arguments. Generally, this creates
a new C<Set> that contains only the elements common to all of the arguments.

    <a b c> (&) <b c d> === set <b c>
    <a b c d> (&) <b c d e> (&) <c d e f> === set <c d>

If any of the arguments are C<Baggy>, the result is a new C<Bag> containing
the common elements, each weighted by the largest I<common> weight (which
is the minimum of the weights of that element over all arguments).

    bag(<a a b c a>) (&) bag(<a a b c c>) === bag(<a a b c>)

=head4 infix ∩ (U+2229 INTERSECTION)

    only sub infix:<<"∩">>(|p)

Equivalent to L«(&)».

=head3 infix (-)

    only sub infix:<(-)>(**@p)

Returns the B<set difference> of all its arguments. Generally, this returns
the C<Set> made up of all the elements the first argument has but the rest
don't, i.e., of all the elements of the first argument, minus the elements
from the other arguments.

If the first argument is C<Baggy>, this returns a C<Bag> that contains each
element of the first argument with its weight subtracted by the weight of
that element in each of the other arguments.

    bag(<a a b c a d>) (-) bag(<a a b c c>) = bag(<a d>)
    bag(<a a a a c d d d>) (-) bag(<a b d a>) (-) bag(<d c>) = bag(<a a d d>)

=head4 infix ∖

    only sub infix:<<"\x2216">>(|p)

Equivalent to L«(-)».

=head3 infix (^)

    multi sub infix:<(^)>(Any $a, Any $b --> Setty)
    multi sub infix:<(^)>(Set $a, Set $b --> Setty)

Returns the B<symmetric set difference> of all its arguments, i.e., a C<Set>
made up of all the elements that C<$a> has but C<$b> doesn't and all the
elements C<$b> has but C<$a> doesn't. Equivalent to C<($a ∖ $b) ∪ ($b ∖
$a)>.

=head4 infix ⊖ (U+2296 CIRCLED MINUS)

    only sub infix:<<"⊖">>($a, $b --> Setty)

Equivalent to L«(^)».

=head3 infix (.)

    only sub infix:<(.)>(**@p)

Returns the Baggy B<multiplication> of its arguments, i.e., a C<Bag> that
contains each element of the arguments with the weights of the element
across the arguments multiplied together to get the new weight.

    <a b c> (.) <a b c d> === bag <a b c> # Since 1 * 0 == 0, in the case of 'd'
    bag(<a a b c a d>) (.) bag(<a a b c c>) === bag(<a a a a a a b c c>)

=head4 infix ⊍ (U+228D MULTISET MULTIPLICATION)

    only sub infix:<<"⊍">>(|p)

Equivalent to L«(.)».

=head3 infix (+)

    only sub infix:<(+)>(**@p)

Returns the Baggy B<addition> of its arguments, i.e., a C<Bag> that contains
each element of the arguments with the weights of the element across the
arguments added together to get the new weight.

    bag(<a a b c a d>) (.) bag(<a a b c c>) === bag(<a a a a a b b c c c d>)


=head4 infix ⊎ (U+228E MULTISET UNION)

    only sub infix:<<"⊎">>(|p)

Equivalent to L«(+)».

=end pod
