Функциональное мышление (2) — почему вы не можете думать об использовании сокращения

внешний интерфейс JavaScript функциональное программирование

В прошлый раз я написал краткое введение в функциональное мышлениестатья, студенты в нашей группе проявили интерес после прочтения. Я надеюсь, что у меня будет время написать больше об этом содержании, а затем сказал, что он может думать о карте с использованием массивов, но он не может думать о редукции. Я думаю, что это также может быть распространенным явлением, потому что для студентов, мало знакомых с FP (функциональным программированием), представление о карте в их сознании может быть в основном эквивалентно циклам, но они относительно незнакомы с редукцией. Но на самом деле, reduce — это более общая функция, чем map, flatMap и т. д. С помощью reduce можно легко реализовать и другие функции.

Давайте сначала реализуем сокращение:

const reduce = (reducer, acc) => list => {
    const [head, ...rest] = list;
    if (head === undefined) return acc;

    return reduce(reducer, reducer(acc, head))(rest);
};

в JSArray.prototype.reduceНемного отличается от моего, его редуктор может принимать четыре параметра (больше currentIndex и массива, чем моя версия). Параметром currentIndex он говорит нам, что его реализация, скорее всего, будет осуществляться через циклы. Честно говоря, лично я чувствую Последние два параметры в принципе бесполезны, а реализации на других языках вообще не имеют этих двух параметров.

Тогда объясните, почему моя редукция не получает напрямую три параметра, а использует форму частичного применения, сначала получает два, а возвращает функцию, которая получает один параметр? Это для повторного использования.Давайте рассмотрим пример.Используйте сокращение для реализации функции суммы для накопления элементов в массиве:

const arr = [1, 2, 3]; // 下文所有的 arr 都是这个

const sum = reduce((acc, x) => acc + x, 0);
sum(arr); // => 6

редукция будет возвращать разные функции при получении разных редукторов и акк, вот сумма возврата, она очень гладкая? И если бы сокращение было функцией, которая принимает три аргумента, тогда сумма должна была бы бытьconst sum = (arr) => reduce((acc, x) => acc + x, 0, arr), не невозможно, а скорее некрасиво.

Далее мы используем reduce для реализации других методов массивов: length, map, flatMap, include, find

// JS 的 Array.length 跟我这个实现不一样,
// arr[100] = 1,arr.length 就为 101 了,因为 JS 的 Array 本质是对象
const length = reduce(acc => acc + 1, 0);
length(arr); // => 3

const map = func => reduce((acc, x) => [...acc, func(x)], []);
map(x => x + 1)(arr); // => [2, 3, 4]

const flatMap = func => reduce((acc, x) => [...acc, ...func(x)], []);
flatMap(x => [x + 1])(arr); // => [2, 3, 4]

const includes = element => reduce((acc, x) => acc || (x === element), false);
includes(1)(arr); // => true

// 找到第一个符合条件的元素返回,否则返回 undefined
const find = func => reduce((acc, x) => acc || (func(x) ? x : undefined), undefined);
find(x => x > 2)(arr); // => 3

Иногда, когда мы обрабатываем строки, мы также хотим использовать сокращение, сопоставление и т. д., тогда мы добавляем в String.prototype:

// string
String.prototype.reduce = function (reducer, acc) {
    return reduce(reducer, acc)(this.split(''));
};

String.prototype.map = function (func) {
    return map(func)(this.split('')).join('');
};

const str = '123';
str.reduce((acc, x) => acc + Number(x), 0); // => 6
str.map(x => Number(x) + 1); // => '234'

эммммммм... так и есть.