Мы продолжаем нашу серию, узнав о методе Array.prototype.reduce () и о функторах что и почему.

Эта статья является частью серии, начинающейся с Примеры функционального программирования на JavaScript: Часть 1. Они написаны не как отдельные статьи, а как (неофициальные) дополнения к серии Эрика Эллиота по функциональному программированию.

Все примеры из этой (моей) серии доступны для скачивания. Это приложения Node.js (версия ≥ 8.9.3).

Уменьшить

В статье Reduce (программное обеспечение для создания) Эрик Эллиот рассказывает о методе Array.prototype.reduce (). Это было некоторое время, начиная с ES 5.1 (июнь 2011 г.), но за все время разработки JavaScript я никогда не использовал его. Интересно то, что я регулярно использовал Array.prototype.map () и Array.prototype.filter (), которые были представлены одновременно.

Вспоминая свои проекты, я подумал о примерах, в которых я мог бы использовать метод Array.prototype.reduce (). В частности, скажем, я хотел сложить нечетные значения в массив чисел (реализованный сначала императивно и декларативно с использованием нашего нового подхода).

reduce / index.js

/* eslint-disable no-console */
const myArray = [1, 2, 3];
// IMPERATIVE
let total = 0;
for (let i = 0; i < myArray.length; i += 1) {
  const myArrayItem = myArray[i];
  if (myArrayItem % 2 !== 0) {
    total += myArrayItem;
  }
}
console.log(total);
// DECLARATIVE
console.log(myArray.reduce(
  (accumulator, currentValue) => (
    currentValue % 2 !== 0 ? accumulator + currentValue : accumulator
  ),
  0,
));

Наблюдения:

  • Хотя этот пример является искусственным, он похож на реальные проблемы, над которыми я работал.
  • Я всегда с подозрением отношусь к ключевому слову let (предупреждающий знак запаха кода); должен был знать, что есть лучший способ сделать это.

Функтор

Читая следующую статью Эрика Функторы и категории, он хорошо справляется с определением функторов и того, как массивы JavaScript являются функторами. В то же время я сначала смутил его пример функтора Identity; С рекурсивным кодом мне всегда приходится больше думать.

const Identity = value => ({
  map: fn => Identity(fn(value))
});

Я нашел старую статью, которую счел полезной, так как дал ряд других примеров функторов, использующих JavaScript. Прочитав это, понять пример Identity стало намного проще.



Что такое функтор?
Это моя попытка объяснить концепцию функционального программирования, называемую« функтором
, простым для понимания способом… средой. com »



Однако, прочитав обе статьи, я изо всех сил пытался понять, почему функторы вообще так важны. Лучшее, что у меня получилось, было:

Функторы - это отличные абстракции более высокого порядка, которые позволяют создавать множество универсальных функций, которые будут работать с любым типом данных.

- Эрик Эллиот

Я потратил нетривиальное время на поиск в сети с такими фразами, как; зачем функторы в программировании. Только когда я прочитал следующую статью, я понял всю суть.



Я проиллюстрирую пользу на примере. Представьте, что мы написали две невероятно сложные функции, например myFunction и trace, которые работают с числами и возвращают другие числа.

В то же время мы сохранили числа в различных структурах (контекстах или ящиках), например, myArray и myFunctor. Поскольку и myArray, и myFunctor являются функторами (со свойством map), мы можем использовать как myFunction, так и отслеживать функции на них (повторное использование кода). Повторное использование кода - это хорошо, и это ответ на вопрос, почему.

функторы / index.js

/* eslint-disable no-console */
// REUSED CODE
const myFunction = x => x * 2;
const trace = (x) => {
  console.log(x);
  return x;
};
// ARRAY FUNCTOR
const myArray = [1, 2, 3];
myArray.map(trace); // 1 \n 2 \n 3
myArray.map(myFunction).map(trace); // 2 \n 4 \n 6
// CUSTOM FUNCTOR
const Identity = value => ({
  map: fn => Identity(fn(value)),
});
const myFunctor = Identity(1);
myFunctor.map(trace); // 1
myFunctor.map(myFunction).map(trace); // 2

Дальнейшие действия

Мы исследуем различные стратегии повторного использования кода в Примеры функционального программирования JavaScript: Часть 3.