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

=TITLE class Mix

=SUBTITLE Immutable collection of distinct objects with Real weights

    class Mix does Mixy { }

A C<Mix> is an immutable collection of distinct elements
in no particular order that each have a real-number weight assigned to
them. (For I<mutable> mixes, see L<MixHash|/type/MixHash> instead.)

C<Mix>es are often used for performing weighted random selections - see
L<.roll|/routine/roll>.

Objects/values of any type are allowed as mix elements. Within a C<Mix>,
items that would compare positively with the L<===|/routine/===> operator are
considered the same element, with a combined weight.

=begin code
my $recipe = (butter => 0.22, sugar => 0.1,
              flour => 0.275, sugar => 0.02).Mix;

say $recipe.elems;      # OUTPUT: «3␤»
say $recipe.keys.sort;  # OUTPUT: «butter flour sugar␤»
say $recipe.pairs.sort; # OUTPUT: «"butter" => 0.22 "flour" => 0.275 "sugar" => 0.12␤»
say $recipe.total;      # OUTPUT: «0.615␤»
=end code

C<Mix>es can be treated as object hashes using the
L«C<{ }> postcircumfix operator|/language/operators#postcircumfix_{_}»,
or the
L«C< < > > postcircumfix operator|/language/operators#postcircumfix_<_>»
for literal string keys, which
returns the corresponding numeric weight for keys that
are elements of the mix, and C<0> for keys that aren't:

    my $recipe = (butter => 0.22, sugar => 0.1,
                  flour => 0.275, sugar => 0.02).Mix;
    say $recipe<butter>;     # OUTPUT: «0.22␤»
    say $recipe<sugar>;      # OUTPUT: «0.12␤»
    say $recipe<chocolate>;  # OUTPUT: «0␤»

=head1 Creating C<Mix> objects

C<Mix>es can be composed using the L<mix|#sub mix> subroutine (or
C<Mix.new>, for which it is a shorthand). Any positional parameters,
regardless of their type, become elements of the mix - with a weight of
C<1> for each time the parameter occurred:

    my $n = mix "a", "a", "b" => 0, 3.14, π, π; # The Pair is a single element
    say $n.keys.map: *.^name; # OUTPUT: «(Rat Pair Num Str)␤»
    say $n.pairs;
    # OUTPUT: «(3.14 => 1 (b => 0) => 1 3.141592653589793 => 2 a => 2)␤»

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

    my $n = ("a", "a", "b" => 0, "c" => 3.14).Mix;
    say $n.keys.map(&WHAT);  # OUTPUT: «((Str) (Str))␤»
    say $n.pairs;            # OUTPUT: «(a => 2 c => 3.14)␤»

Elements with a 0 value, as C<b> above, are simply eliminated from the C<Mix>.

Alternatively, since C<Mix>es are L<Associative|/type/Associative>, we can use the C<%> sigil to
declare them; in that case, we can employ C<is> to declare their type:

    my %n is Mix = ("a", "a", "b" => 0, "c" => 3.14);
    say %n.^name; # OUTPUT: «Mix␤»
    say %n;       # OUTPUT: «Mix(a(2) c(3.14))␤»

Since 6.d (2019.03 and later) it is also possible to specify the type of values
you would like to allow in a C<Mix>.  This can either be done when calling
C<.new>:

    # only allow strings
    my $n = Mix[Str].new: <a b b c c c>;

or using the masquerading syntax:

    # only allow strings
    my %m is Mix[Str] = <a b b c c c>;
    say %m<b>;  # 2
    say %m<d>;  # 0

    # only allow whole numbers
    my %m is Mix[Int] = <a b b c c 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<Mix>.

Examples:

=begin code
my $this-mix = (sugar => ⅓, spice => ¼, all-things-nice => ¾);
my $that-mix = ( sugar => 1, spice => 2);

say $that-mix (<) $this-mix;     # OUTPUT: «True␤»
say $that-mix (^) $this-mix;     # OUTPUT: «Set(all-things-nice)␤»
say $that-mix (+) $this-mix;     # OUTPUT: «Bag(spice(2) sugar)␤»

# Unicode versions:
say $that-mix ⊂ $this-mix;     # OUTPUT: «True␤»
say $that-mix ⊖ $this-mix;     # OUTPUT: «Set(all-things-nice)␤»
say $that-mix ⊎ $this-mix;     # OUTPUT: «Bag(spice(2) sugar)␤»
=end code

=head2 sub mix

    sub mix(*@args --> Mix)

Creates a new C<Mix> from C<@args>.

=head1 Methods

=head2 method Bag

Defined as:

    method Bag (--> Bag:D)

Coerces the C<Mix> to a L«C<Bag>|/type/Bag». The weights are convert to
L«C<Int>|/type/Int», which means the number of keys in the resulting
C<Bag> can be fewer than in the original C<Mix>, if any of the weights
are negative or truncate to zero.

=head2 method BagHash

Defined as:

    method BagHash (--> BagHash:D)

Coerces the C<Mix> to a L«C<BagHash>|/type/BagHash». The weights are
convert to L«C<Int>|/type/Int», which means the number of keys in the
resulting C<BagHash> can be fewer than in the original C<Mix>, if any of
the weights are negative or truncate to zero.

=head2 method reverse

I<Note>: This method is inherited from L<Any|/type/Any#routine_reverse>,
however, C<Mix>es do not have an inherent order and you should not trust
it returning a consistent output.

=head2 method total

    method total(Mix:D: --> Real)

Returns the sum of all the weights

    say mix('a', 'b', 'c', 'a', 'a', 'd').total == 6;  # OUTPUT: «True␤»
    say %(a => 5.6, b => 2.4).Mix.total == 8;          # OUTPUT: «True␤»

=head2 Note on order

Same as the other elements in the L<Bag/Mix suite|/language/setbagmix>,
order is not guaranteed or consistent and you shouldn't rely on methods
like C<reverse> above returning always the same result.

=head1 See Also

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

=end pod

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