Documentation for routine reduce

Documentation for routine reduce, assembled from the following types:

class Any

From Any

(Any) method reduce

Defined As:

method reduce(&with --> Nil)


class List

From List

(List) routine reduce

Defined as:

multi sub    reduce(&with*@values)
multi method reduce(List:D: &with)

Generates a single "combined" value from a list of arbitrarily many of values, by iteratively applying a function which knows how to combine two values.

If @values contains just a single element, that element is returned immediately. If it contains no elements, an exception is thrown, unless &with is an operator with a known identity value. For this reason, you may want to prefix the input list with an explicit identity value:

my @strings = ("One good string!""And one another good string!");
say reduce { $^a ~ $^b }''|@strings;               # like @strings.join 
my @numbers = (1,2,3,4,5);
say reduce { $^a > $^b ?? $^a !! $^b }0|@numbers;  # like @numbers.max 

If &with is the function object of an operator, its inherent identity value and associativity is respected - in other words, (VAL1, VAL2, VAL3).reduce(&[OP]) is the same as VAL1 OP VAL2 OP VAL3 even for operators which aren't left-associative:

# Raise 2 to the 81st power, because 3 to the 4th power is 81 
[2,3,4].reduce(&[**]).lsb.say;        # OUTPUT: «81␤» 
(2**(3**4)).lsb.say;                  # OUTPUT: «81␤» 
(2**3**4).lsb.say;                    # OUTPUT: «81␤» 
# Subtract 4 from -1, because 2 minus 3 is -1 
[2,3,4].reduce(&[-]).say;             # OUTPUT: «-5␤» 
((2-3)-4).say;                        # OUTPUT: «-5␤» 
(2-3-4).say;                          # OUTPUT: «-5␤» 

Since reducing with an infix operator is a common thing to do, the [ ] meta-operator provides a syntactic shortcut:

# The following all do the same thing... 
my @numbers = (1,2,3,4,5);
say reduce { $^a + $^b }0|@numbers;
say reduce * + *0|@numbers;
say reduce &[+], @numbers# operator does not need explicit identity 
say [+@numbers;          # most people write it this way 

Since reduce is an implicit loop, it responds to next, last and redo statements inside &with:

say (2,3,4,5).reduce: { last if $^a > 7$^a + $^b }# says 9 

Practical example:

# Generate a random-ish math formula like "(4 + ((3 * x) + 11) / 6))" 
my @ops = [Z] (<+ - * />1..20.roll(4);
say ('x'|@ops).reduce: -> $formula, [$op$number{
    Bool.pick ?? "($formula $op $number)"
              !! "($number $op $formula)"

Note: In the functional programming world, this operation is generally called a fold. With a right-associative operator it is a right fold, otherwise (and usually) it is a left fold:

sub infix:<foo>($a$bis assoc<right> { "($a$b)" }
say [foo1234# OUTPUT: «(1, (2, (3, 4)))␤» 
sub infix:<bar>($a$bis assoc<left> { "($a$b)" }
say [bar1234# OUTPUT: «(((1, 2), 3), 4)␤» 

class Supply

From Supply

(Supply) method reduce

method reduce(Supply:D: &with --> Supply:D)

Creates a "reducing" supply with the same semantics as List.reduce.

my $supply = Supply.from-list(1..5).reduce({$^a + $^b});
$supply.tap(-> $v { say "$v" }); # OUTPUT: «15␤»