Элементы функционального программирования
Функциональное программирование(FP) — способ организации кода через написание набора функций.
EcmaScript, являясь мультипарадигменным языком программирования, реализует наряду с прочими и функциональную парадигму. Это означает, что функции в ES являются данными и могут быть переданы в функции, возвращены из функций и могут сами принимать функции. Т.е. функции в ES являются функциями первого класса.
Отсюда следуют следующие определения:
Функциональный агрумент — аргумент, значением которого является функция.
Функция высшего порядка — функция, которая принимает функции в качестве аргументов.
Функции с функциональным значением — функция, которая возвращает функцию.
Давайте на примере посмотрим что к чему.
Мы же знаем, что функция triple вернет другую функцию, которую мы сохранили в переменную triple_bar. А значит что теперь мы можем функцию triple_bar вызвать:
Рекурсия
Рекурсия — определение, описание, изображение какого-либо объекта или процесса внутри самого этого объекта или процесса, то есть ситуация, когда объект является частью самого себя. Термин «рекурсия» используется в различных специальных областях знаний — от лингвистики до логики, но наиболее применение находит в математике и информатике.
Применительно к программированию под рекурсией подразумевают процессы, которые вызывают сами себя в своём теле. Рекурсивная функция имеет несколько обязательных составляющих:
- Терминальное условие — условие прекращения выполнения
- Правило по которому осуществляется движение в глубь по рекурсии
Рассмотрим самый популярный пример рекурсии — вычисление факториала.
Выделим характерные составляющие рекурсивной функции. Терминальное условие
и правило движения по рекурсии
Рекурсия как замена циклу
Вообще мы могли бы даже отказаться от циклов и реализовывать их через рекурсии. Обратите внимание на то, что рекурсиии и циклы похожи по 2 пунктам:
- Цикл повторяет какие-то действия пока выполняется условие, у рекурсии если правило перехода на следующую итерацию, так называемое правило движения по рекурсии.
- Цикл прекращает свою работу при определенном условии (а точнее - при ситуации когда условие не выполняется). С рекурсией что-то похожее.. что называется терминальным условием.
Давайте не будем мусолить и посмотрим на замену следующего цикла c помощью рекурсии. Вот сам цикл:
Что мы здесь видим? Ну то, что "терминальное условие цикла" - это i >= 3. Значит мы можем легко переписать пример через рекурсию:
Вуаля👏👏👏! Если вы прогоните этот код, то результат и там и там будет аналогичным.
Обход дерева
Рекурсию удобно использовать для работы с рекурсивными структурами данных, такими как вложенные списки или деревья.
note
Обратите внимание на определение рекурсии, для того чтобы стало понятнее что такое рекурсивные структуры данных.
Представим следующее дерево:
Да что это за деревья!😡⁉️
Дерево — одна из наиболее широко распространённых структур данных в информатике, эмулирующая древовидную структуру в виде набора связанных узлов. Является связным графом, не содержащим циклы. Большинство источников также добавляют условие на то, что рёбра графа не должны быть ориентированными. В дополнение к этим трём ограничениям, в некоторых источниках указывается, что рёбра графа не должны быть взвешенными.
Как мы понимаем вложенность папок и файлов может быть сколь угодно глубокой. А как нам обработать такую структуру, например вытащить все названия папок? Конечно, мы можем выдумывать с вами алгоритм на циклах(итеративный), но зачем усложнять жизнь? Давайте накинем функцию которая может вытаскивать список файлов из папки:
Что мы сейчас получим если применим функцию getFilesFromFolder к папке в переменной FS_TREE?
В ответ мы получим примерно такой объект:
Нам сейчас останется переписать функцию таким образом чтобы она не просто фильтровала элементы в свойстве children и возвращала только файлы а еще применяла саму себя к тем папкам которые находятся в свойстве children.
Популярные функции высшего порядка
Напоминаю, что функции высшего порядка это те функции которые получают другие функции как свои аргумент или возвращают функции. На постоянной основе вы будете пользоваться HOF-методами массивов: Array.prototype.map(), Array.prototype.filter(), Array.prototype.find(), Array.prototype.forEach() и Array.prototype.reduce().
Array.prototype.map()
Эта функция высшего порядка позволяет нам применить какую-либо функцию к каждому элементу массива и получить массив результатов применения этой функции.
Давайте посмотрим на достаточно простой пример, у нас есть массив чисел:
нам по некоторым причинам требутеся умножить каждый элемент на 2, для этого мы напишем функцию:
и применем ее к каждому элементу в NUMS:
Array.prototype.filter()
Для сортировки массива мы можем воспользоваться тем же циклом.. например для получения всех элементов из массива которые больше чем 100, мы напишем что-то такое:
Но можно это сделать чуть более элегантно с применением метода массива filter, который получает тест-функцию, которая в свою очередь уже говорит, элемент который она получила проходит проверку или нет.
После написания фунции мы можем передать ее в метод filter: