Курс языка программирования Raku / Функциональное, конкурентное, реактивное и веб-программирование / Функциональное программирование / Свёртка

Процедура reduce

Когда сворачивать нужно собственной операцией, а не одним именованным оператором, используйте процедуру reduce. Она принимает блок от двух аргументов и применяет его вдоль списка, перенося накопленный результат дальше:

say (1..5).reduce(* + *); # 15

В блоке * + * две звезды Whatever: первая — это результат, накопленный к этому моменту, вторая — очередной элемент. Поэтому reduce вычисляет ((((1 + 2) + 3) + 4) + 5), то есть 15, — то же, что и [+], но записанное блоком.

Чтобы увидеть эти два аргумента в деле, дайте им имена и напечатайте каждый шаг. Стрелочный блок возвращает своё последнее выражение, поэтому $x + $y — это и то, о чём блок печатает, и то значение, которое он возвращает в reduce:

say (1..5).reduce(
    -> $x, $y {
        say "$x + $y";
        $x + $y;
    }
);

Программа печатает:

1 + 2
3 + 3
6 + 4
10 + 5
15

Каждая из первых четырёх строк — это один вызов блока. $x — накопленный к этому моменту результат, $y — очередной элемент списка. Самый первый вызов получает два первых значения списка, 1 и 2; каждый следующий получает обратно итог предыдущего шага как $x3, затем 6, затем 10, — в паре с очередным числом как $y. Значение блока становится $x следующего вызова, а итоговая сумма, 15, — это то, что reduce возвращает и что say печатает последней строкой.

Поскольку блок может быть каким угодно, reduce более универсален. Например, можно строить значение шаг за шагом:

say (1..4).reduce(-> $acc, $x { $acc * 10 + $x }); # 1234

Каждый шаг умножает накопитель на десять и прибавляет очередную цифру, превращая отдельные цифры 1, 2, 3, 4 в число 1234.

Как и другие принимающие блок методы, reduce хорошо читается в форме вызова с двоеточием, где скобки вокруг блока опускаются:

say (1..5).reduce: * + *; # 15

Коротко говоря, [op] — быстрая форма для именованного оператора, а reduce — гибкая форма для произвольного объединяющего блока. Оба сворачивают список к одному значению.

Практика

Пройдите 1 тест по содержанию этой темы.

Навигация по курсу

Тест — Метаоператор свёртки   |   Тест — Свёртка


💪 Или перейдите сразу к упражнениям этого раздела.