routine reduce
Documentation for routine reduce
assembled from the following types:
class Supply
From Supply
(Supply) method reduce
method reduce(Supply: --> Supply)
Creates a "reducing" supply with the same semantics as List.reduce.
my = Supply.from-list(1..5).reduce();.tap(-> ); # OUTPUT: «15»
class Any
From Any
(Any) method reduce
Defined as:
multi method reduce(Any: & --> Nil)multi method reduce(Any: )multi sub reduce (, +list)
Applying it to a class will always produce Nil. Applies its argument (or first argument, in case it's a sub) as an operator to all the elements in the object (or second argument), producing a single result. The argument must be an infix operator or take, in any case, two positional arguments.
(1..13).reduce( &[*] ).say; # OUTPUT: «6227020800»
class List
From List
(List) routine reduce
Defined as:
multi method reduce(Any: & --> Nil)multi method reduce(Any: )multi sub reduce (, +list)
The first form is obviously a no-op. The second form generates a single "combined" value from a list of arbitrarily many values, by iteratively applying a function which knows how to combine two values.
If @values
contains just a single element, the operator is applied to that single element if possible; if not, it returns the element itself.
say [-] <10 5 3>; #OUTPUT: 2say [-] 10; #OUTPUT: 10
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 = ("One good string!", "And one another good string!");say reduce , '', |; # like @strings.joinmy = (1,2,3,4,5);say reduce , 0, |; # 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 [ ]
metaoperator provides a syntactic shortcut:
# The following all do the same thing...my = (1,2,3,4,5);say reduce , 0, |;say reduce * + *, 0, |;say reduce &[+], ; # operator does not need explicit identitysay [+] ; # most people write it this way
Please note also the use of reduce
in sub form. Since reduce
is an implicit loop, it responds to next
, last
and redo
statements inside &with
:
say (2,3,4,5).reduce: ; # says 9
Practical example:
# Generate a random-ish math formula like "(4 + ((3 * x) + 11) / 6))"my = [Z] (<+ - * />, 1..20)».roll(4);say ('x', |).reduce: -> , [, ]
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>(, ) is assoc<right>say [foo] 1, 2, 3, 4; # OUTPUT: «(1, (2, (3, 4)))»sub infix:<bar>(, ) is assoc<left>say [bar] 1, 2, 3, 4; # OUTPUT: «(((1, 2), 3), 4)»