# The Reduction Meta Operator

### NAME

"Perl 5 to 6" Lesson 24 - The Reduction Meta Operator

### SYNOPSIS

```    say [+] 1, 2, 3;    # 6
say [+] ();         # 0
say [~] <a b>;      # ab
say [**] 2, 3, 4;   # 2417851639229258349412352

[\+] 1, 2, 3, 4     # 1, 3, 6, 10
[\**] 2, 3, 4       # 4, 81, 2417851639229258349412352

if [<=] @list {
say "ascending order";
}```

### Description

The reduction meta operator `[...]` can enclose any associative infix operator, and turn it into a list operator. This happens as if the operator was just put between the items of the list, so `[op] \$i1, \$i2, @rest` returns the same result as if it was written as `\$i1 op \$i2 op @rest[0] op @rest[1] ...`.

This is a very powerful construct that promotes the plus `+` operator into a `sum` function, `~` into a `join` (with empty separator) and so on. It is somewhat similar to the `List.reduce` function, and if you had some exposure to functional programming, you'll probably know about `foldl` and `foldr` (in Lisp or Haskell). Unlike those, `[...]` respects the associativity of the enclosed operator, so `[/] 1, 2, 3` is interpreted as `(1 / 2) / 3` (left associative), `[**] 1, 2, 3` is handled correctly as `1 ** (2**3)` (right associative).

Like all other operators, whitespace are forbidden, so you while you can write `[+]`, you can't say `[ + ]`. (This also helps to disambiguate it from array literals).

Since comparison operators can be chained, you can also write things like

```    if    [==] @nums { say "all nums in @nums are the same" }
elsif [<]  @nums { say "@nums is in strict ascending order" }
elsif [<=] @nums { say "@nums is in ascending order"}```

However you cannot reduce the assignment operator:

```    my @a = 1..3;
[=] @a, 4;          # Cannot reduce with = because list assignment operators are too fiddly```

#### Getting partial results

There's a special form of this operator that uses a backslash like this: `[\+]`. It returns a list of the partial evaluation results. So `[\+] 1..3` returns the list `1, 1+2, 1+2+3`, which is of course `1, 3, 6`.

`    [\~] 'a' .. 'd'     # <a ab abc abcd>`

Since right-associative operators evaluate from right to left, you also get the partial results that way:

`    [\**] 1..3;         # 3, 2**3, 1**(2**3), which is 3, 8, 1`

Multiple reduction operators can be combined:

`    [~] [\**] 1..3;     # "381"`

### MOTIVATION

Programmers are lazy, and don't want to write a loop just to apply a binary operator to all elements of a list. `List.reduce` does something similar, but it's not as terse as the meta operator (`[+] @list` would be `@list.reduce(&infix:<+>)`). Also with reduce you have to takes care of the associativity of the operator yourself, whereas the meta operator handles it for you.

If you're not convinced, play a bit with it (rakudo implements it), it's real fun.