Функциональное программирование lambda

Коди Арсено
Опубликовано 24 августа 2017 года
Функциональное Программирование - Что Это Такое и Почему Оно Имеет Значение?

Хотя эта концепция существует уже довольно давно, функциональное программирование, наконец. Вышло из безвестности на передний план сообщества JavaScript несколько лет назад. Разработчики крупных приложений теперь регулярно включают его принципы в свою кодовую базу. Если вы новичок в функциональном программировании, это руководство поможет вам быстро освоиться.

Что такое функциональное программирование?#

Функциональное программирование (FP) — это парадигма программирования для разработки программного обеспечения с использованием функций. Следование философии FP влечет за собой такие вещи, как общие состояния, изменчивые данные и побочные эффекты. Функциональное программирование является декларативной парадигмой, поскольку оно опирается на выражения и объявления. А не на операторы В отличие от процедур. Зависящих от локального или глобального состояния. Выходные значения в FP зависят только от аргументов. Переданных функции. Принятие внешних эффектов или изменений состояния, которые не зависят от входных данных функций. Делает программное обеспечение более предсказуемым. Что является основным преимуществом для многих программистов FP.

Код, написанный с учетом принципов ФП, называется функциональным кодом.

Другая парадигма программирования . Более знакомая обычным программистам,-это объектно-ориентированное программирование, или ООП. Которое использует преимущества состояний и методов приложений. В наши дни ООП гораздо более распространена, чем ФП.

тенденции фп и ооп

Однако функциональный код часто более сжат и легче тестируется, хотя на первый взгляд новичкам он может показаться непонятным. FP имеет крутую кривую обучения, поэтому не ожидайте, что вы узнаете все, что вам нужно знать о нем, из одного урока. Тем не менее, если у вас достаточно опыта работы с JavaScript, вы, скорее всего. Включили некоторые концепции функционального программирования в свой код, возможно. Даже не зная об этом.

Терминология функционального программирования#

Прежде чем вы сможете стать экспертом по ФП, вам необходимо понять некоторые жаргонные термины:

Чистые функции#

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

Функциональный состав#

Функциональная композиция означает объединение функций для создания новой или выполнения вычисления.

Одна точка используется для объединения функций, поэтому композиция a . bозначает то же a(b(x))самое, что и в JavaScript.

Общие состояния#

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

Избегание общих состояний гарантирует, что время и порядок вызовов функций не влияют на результаты вычислений. Таким образом, вызовы функций остаются полностью независимыми друг от друга. Что делает рефакторинг и другие изменения менее головной болью. Хотя порядок операций все еще остается в силе, все, что происходит с переменными вне функции, не влияет на их значение в FP. В противном случае вам придется знать историю каждой переменной.

Неизменность#

Поскольку FP не зависит от общих состояний. Все данные в функциональном коде должны быть неизменяемымиили неспособными к изменению.

Не путайте неизменяемость с объявлением const JavaScript, которое используется для привязки переменных. Чтобы сделать значение неизменным, вы можете глубоко заморозить его. JavaScript предлагает метод замораживания объектов на один уровень глубже. Но это все еще не делает их полностью неизменяемыми.

Функциональные языки программирования используют преимущества так называемых структур данных trie. Произносимые как Благодаря процессу структурного обмена они потребляют меньше памяти и, следовательно, работают лучше. Чем традиционные структуры данных. GitHub имеет библиотеки JavaScript для нескольких различных структур данных trie включая

Immutable.js и Мори.

Побочные эффекты#

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

монадами.

Основы функционального программирования#

Чистые функции работают только со своими входными параметрами. Возьмем следующий код JavaScript:

var z = 15; function add(x, y) { return x + y; }

Поскольку zпеременная не включена в функцию add, функция только считывает и записывает данные на свои входы xy. Следовательно. Функция чиста. zЭто сделало бы его нечистым.

Чтобы быть полезными. Чистые функции должны принимать параметры и возвращать что-то. Вы можете использовать вышеприведенную чистую функцию следующим образом:

function add(x, y) { return x + y; } console.log(add(1, 2)); 

Чистые функции всегда возвращают один и тот же результат, когда задаются одни и те же входные данные. Такие функции , какwriteFile(fileName), updateDatabaseTable(sqlCmd)и sendAjaxRequest(ajaxRequest)не являются чистыми. Потому что они влияют на внешние переменные и. Следовательно. Имеют побочные эффекты. Которые невозможно предсказать.

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

Переменные, которые не меняются#

Чтобы проиллюстрировать разницу между императивным и функциональным программированием. Давайте рассмотрим небольшой пример кода:

var x = 1; x = x + 1;

В императивном программировании это означает. Что берут текущее значение x, добавляют 1и помещают результат обратно x. В функциональном программировании, однако, x = x + 1это незаконно. Это потому, что в функциональном программировании технически нет переменных. Хотя мы все еще называем сохраненные значения переменными в FP. Эти значения всегда одинаковы. Поэтому они на самом деле не меняются.

Как можно чего-то добиться без переменных? Используя неизменяемые структуры данных. Вы можете вносить одно-или многозначные изменения , копируя переменные и вычисляя новые значения, что более подробно обсуждается в следующем разделе.

Цикличность в функциональном программировании#

Функциональное программирование не использует циклические конструкции , такие какrepeat, forи while. Вместо этого он полагается на рекурсию для цикличности. Возьмем следующие примеры JavaScript:

var acc = 0; for (var i = 1; i  10; ++i) acc += i; console.log(acc); 

Простая конструкция цикла может быть сделана функциональной следующим образом:

function sumRange(start, end, acc) { if (start > end) return acc; return sumRange(start + 1, end, acc + start) } console.log(sumRange(1, 10, 0)); 

Эти два совершенно разных подхода дают вам одну и ту же ценность, 55. В последнем примере рекурсия выполняет ту же задачу, что и цикл, вызывая себя с новым началом и новым аккумулятором. Исходные значения не изменяются; скорее. Новые значения вычисляются с использованием старых.

Хотя функциональное программирование возможно в JavaScript, возможно. Имеет смысл использовать язык. Специально разработанный для этого. Вот как будет выглядеть приведенный выше пример на языке Elm:

sumRange start end acc = if start > end then acc else sumRange (start + 1) end (acc + start) 

Код немного более оптимизирован. И вы все равно получаете значение 55. В то время как использование циклов может выглядеть менее пугающим для вас прямо сейчас. Использование рекурсии позволяет вам сохранять вещи неизменными. Одно из самых больших преимуществ неизменности заключается в том, что. Поскольку у вас есть только доступ для чтения к значениям, вам не нужно беспокоиться о том. Что кто-то случайно изменит их и вызовет проблемы.

Повторное использование и функции более высокого порядка#

Еще одним преимуществом функционального программирования является то. Что оно облегчает повторное использование функциональных утилит для более эффективной обработки данных. В отличие от ООП. Которая размещает методы и данные в объектах так. Что они могут работать только с определенными типами данных. Все типы данных являются честной игрой в функциональном программировании.

К счастью, JavaScript предлагает первоклассные функции. Что означает. Что они могут обрабатываться как данные. Присваиваться переменным и передаваться другим функциям. Например, можно использовать функцию высшего порядка map()для отображения чисел. Объектов и строк. Функции более высокого порядка принимают другие функции в качестве аргументов или возвращают другие функции. Они полезны для создания утилит. Которые могут действовать на многих различных типах данных. Частично применяя функции к своим аргументам или создавая функции карри для повторного использования.

Кстати говоря, функции более высокого порядка map()и reduce()предлагают лучшую альтернативу итерации по спискам. Если у вас есть функция и коллекция элементов, map()вы можете запустить эту функцию для каждого элемента и вставить возвращаемые значения в новую коллекцию. Например, эта простая карта, написанная на Python 2, принимает список имен и возвращает длину символов этих имен:

name_lengths = map(len, ["Bob", "Rob", "Bobby"]) print name_lengths // [3, 3, 5]

Вот еще одна карта. Которая заключает в квадраты каждое число в коллекции:

squares = map(lambda x: x * x, [0, 1, 2, 3, 4]) print squares // [0, 1, 4, 9, 16]

Как вы можете видеть. В приведенном выше примере нет именованной функции. Вместо этого карта принимает встроенную анонимную функцию. Определенную с помощью лямбды. Функциональное программирование основано на лямбда-исчислении, поэтому все, что вы узнаете об этом предмете. Поможет вашему кодированию FP. В этом примере параметры лямбды определяются с левой стороны двоеточия. А тело функции-с правой стороны.

Теперь давайте сделаем некоторые нефункциональные коды функциональными. Следующий код случайным образом назначает список людей одной из двух команд:

import random names = ['Seth', 'Ann', 'Morganna'] team_names = ['A Team', 'B Team'] for i in range(len(names)): names[i] = random.choice(team_names) print names // ['A Team', 'B Team', 'B Team']

Используя функциональные принципы. Мы можем переписать код в виде карты:

import random names = ['Seth', 'Ann', 'Morganna'] team_names = map(lambda x: random.choice(['A Team', 'B Team']), names)

reduce() является еще одной функцией более высокого порядка для выполнения итераций. Он принимает функции и коллекции элементов. А затем возвращает значение объединения элементов. Вот простой пример. Который выводит сумму набора чисел:

sum = reduce(lambda a, x: a + x, [0, 1, 2, 3, 4]) print sum // 10

xПеременная представляет элемент, который в данный момент повторяется, а aпеременная-это аккумулятор или значение. Возвращаемое после выполнения лямбды для предыдущего элемента. В первой итерации aон принимает значение первого элемента, поэтому итерация начинается только со второго элемента. Поэтому первоеx-это фактически второй пункт. Когда reduce()функция повторяется. Она запускает лямбду по текущим aпеременным и xпеременным. И результат становится aрезультатом следующей итерации.

Сначала вам может быть трудно увидеть преимущества использования map()итераций и reduce()для итераций. Но их использование может обеспечить несколько преимуществ для общего кода программы. Есть также другие функции более высокого порядка, такие как filter()иfold(), с которыми вы должны ознакомиться. Если хотите стать профессионалом FP.

Декларативное против императивного#

Поскольку функциональное программирование является декларативной парадигмой. Логика программы выражается без явных инструкций для управления потоком. В то время как императивные программы посвящают много строк кода управлению потоком. Декларативные программы абстрагируют процесс.

Например, следующее императивное отображение принимает массив чисел и возвращает другой массив с каждым числом. Умноженным на 3:

const tripleMap = numbers => { const triple = []; for (let i = 0; i  numbers.length; i++) { triple.push(numbers[i] * 3); } return triple; }; console.log(tripleMap([5, 6, 7])); 

То же самое можно сделать с декларативным отображением гораздо более лаконично благодаря функциональной Array.prototype.map()утилите:

const tripleMap = numbers => numbers.map(n => n * 3); console.log(tripleMap([5, 6, 7])); 

Императивный код часто использует операторы типа for, ifи switch. Декларативный код. С другой стороны, в большей степени зависит от выражений. Выражения-это части кода, которые вычисляют и возвращают значение, поэтому они состоят из таких вещей, как вызовы функций. Значения и операторы. В FP выражения могут быть назначены идентификаторам. Возвращены из функций или переданы в функцию.

Резюме#

Работа в индустрии веб-разработки требует адаптивности. Чем больше вы знаете. Тем больше возможностей у вас будет для развития своей карьеры. Если вы не будете продолжать расширять свой репертуар навыков, вы можете оказаться неспособным конкурировать на рынке труда.

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