=begin pod :kind("Type") :subkind("class") :category("composite")

=TITLE class Set

=SUBTITLE Immutable collection of distinct objects

    class Set does Setty { }

A C<Set> is an immutable set, meaning a collection of distinct elements in no
particular order. (For I<mutable> sets, see L<SetHash|/type/SetHash> instead.)

Objects/values of any type are allowed as set elements. Within a C<Set>, every
element is guaranteed to be unique (in the sense that no two elements would
compare positively with the L<===|/routine/===> operator):

=begin code
my $fruits = set <peach apple orange apple apple>;

say $fruits.elems;      # OUTPUT: «3␤»
say $fruits.keys.sort;  # OUTPUT: «apple orange peach␤»
=end code

C<Set>s can be treated as object hashes using the C<{ }> postcircumfix operator,
which returns the value C<True> for keys that are elements of the set, and
C<False> for keys that aren't:

    my $fruits = set <peach apple orange apple apple>;
    say $fruits<apple>;  # OUTPUT: «True␤»
    say $fruits<kiwi>;   # OUTPUT: «False␤»

=head1 Creating C<Set> objects

C<Set>s can be composed using the L<set|#sub set> subroutine (or C<Set.new>, for
which it is a shorthand). Any positional parameters, regardless of their type,
become elements of the set:

    my $n = set "zero" => 0, "one" => 1, "two" => 2;
    say $n.keys.raku;        # OUTPUT: «(:two(2), :zero(0), :one(1)).Seq␤»
    say $n.keys.map(&WHAT);  # OUTPUT: «((Pair) (Pair) (Pair))␤»

Alternatively, the C<.Set> coercer (or its functional form, C<Set()>) can be
called on an existing object to coerce it to a C<Set>. Its semantics depend on
the type and contents of the object. In general it evaluates the object in list
context and creates a set with the resulting items as elements, although for
Hash-like objects or Pair items, only the keys become elements of the set - and
keys mapped to values which boolify to C<False> are skipped:

    my $n = ("zero" => 0, "one" => 1, "two" => 2).Set;
    say $n.keys.raku;        # OUTPUT: «("one", "two").Seq␤»
    say $n.keys.map(&WHAT);  # OUTPUT: «((Str) (Str))␤»

Furthermore, you can get a C<Set> by using set operators (see next section) on
objects of other types such as L<List|/type/List>, which will act like they
internally call C<.Set> on them before performing the operation. Be aware of
the tight precedence of those operators though, which may require you to use
parentheses around arguments:

    say (1..5) (^) 4;  # OUTPUT: «Set(1 2 3 5)␤»

Of course, you can also create a C<Set> with the C<.new> method.

    my $fruits = Set.new( <peach apple orange apple apple> );

Since 6.d (2019.03 and later) you can also use this syntax for parameterization
of the C<Set>, to specify which type of values are acceptable:

    # only allow strings (Str) in the Set
    my $fruits = Set[Str].new( <peach apple orange apple apple> );

    # only allow whole numbers (Int) in the Set
    my $fruits = Set[Int].new( <peach apple orange apple apple> );
    # Type check failed in binding; expected Int but got Str ("peach")

Finally, you can create Set masquerading as a hash by using the C<is> trait:

    my %s is Set = <a b c>;
    say %s<a>;  # True
    say %s<d>;  # False

Since 6.d (2019.03 and later), this syntax also allows you to specify the
type of values you would like to allow:

    # limit to strings
    my %s is Set[Str] = <a b c>;
    say %s<a>;  # True
    say %s<d>;  # False

    # limit to whole numbers
    my %s is Set[Int] = <a b c>;
    # Type check failed in binding; expected Int but got Str ("a")

=head1 Operators

See L<Operators with set
semantics|/language/setbagmix#Operators_with_set_semantics> for a complete
list of "set operators" applicable to, among other types, C<Set>.

Examples:

=begin code
my ($a, $b) = set(1, 2, 3), set(2, 4);

say $a (<) $b;  # OUTPUT: «False␤»
say $a (&) $b;  # OUTPUT: «Set(2)␤»
say $a (^) $b;  # OUTPUT: «Set(1 3 4)␤»

# Unicode versions:
say $a ⊂ $b;  # OUTPUT: «False␤»
say $a ∩ $b;  # OUTPUT: «Set(2)␤»
say $a ⊖ $b;  # OUTPUT: «Set(1 3 4)␤»
=end code

=head1 Subroutines

=head2 sub set

    sub set(*@args --> Set)

Creates a C<Set> from the given C<@args>

=head1 See Also

L<Sets, Bags, and Mixes|/language/setbagmix>

=end pod

# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
