После длительного обучения и работы с объектно-ориентированным программированием я сделал шаг назад, чтобы подумать о сложности системы.
Делать некоторые исследования, я нашел функциональные концепции программирования, такие как неподумность и чистая функция. Эти концепции являются большие преимущества для создания функций без боковых эффектов, поэтому легче поддерживать системы – с некоторыми другими преимущества .
В этом посте я расскажу вам больше о функциональном программировании, а некоторые важные концепции, с большим количеством примеров кода.
Эта статья использует Clojure в качестве примера языка программирования для объяснения функционального программирования. Если вам не комфортно с языком Lisp-типа, я также опубликовал тот же пост в JavaScript. Посмотреть: Функциональные принципы программирования в JavaScript
Что такое функциональное программирование?
Чистые функции
Первая фундаментальная концепция мы узнаем, когда мы хотим понять функциональное программирование, это Чистые функции Отказ Но что это действительно значит? Что делает функцию чистой?
Так как мы знаем, если функция чистый
или не? Вот очень строгое определение чистоты:
- Он возвращает тот же результат, если учесть те же аргументы (он также называется как
детерминированные
) - Это не вызывает наблюдаемых побочных эффектов
Это возвращает тот же результат, если учесть те же аргументы
Представьте, что мы хотим реализовать функцию, которая рассчитывает область круга. Нечистая функция получила бы Радиус
Как параметр, а затем рассчитать RADIUS * RADIUS * PI
Отказ В Clojure оператор наступает на первом месте, так RADIUS * RADIUS * PI
становится (* Radius Radius Pi)
:
Почему эта нечистая функция? Просто потому, что он использует глобальный объект, который не был передан в качестве параметра к функции.
Теперь представьте, что некоторые математики утверждают, что PI
Значение на самом деле 42 и изменить значение глобального объекта.
Наша нечая функция теперь приведет к 10 * 10 * 42
= 4200
Отказ Для того же параметра ( RADIUS
), у нас есть другой результат. Давайте исправим это!
Та-да?! Теперь мы всегда будем проходить тепла Я
значение в качестве параметра к функции. Итак, теперь мы просто доступ к параметрам, передаваемым к функции. Нет е Xternal Object.
- Для параметров
Радиус
&PI.14
У нас всегда будет тот же результат:314.0
- Для параметров
Радиус
&PI
У нас всегда будет тот же результат:4200.
Чтение файлов
Если наша функция читает внешние файлы, это не чистая функция – содержимое файла может измениться.
Случайное количество поколений
Любая функция, которая опирается на генератор случайного номера, не может быть чистым.
Это не вызывает наблюдаемых побочных эффектов
Примеры наблюдаемых побочных эффектов включают в себя модификацию глобального объекта или параметра, передаваемого ссылкой.
Теперь мы хотим реализовать функцию для получения целочисленного значения и возврата значения увеличенного на 1.
У нас есть счетчик
ценить. Наша нечая функция получает эту ценность и повторно назначает счетчик со значением, увеличенным на 1.
Наблюдение : Мутурмамность обескуражена в функциональном программировании.
Мы изменяем глобальный объект. Но как бы мы сделали это чистый
? Просто верните значение увеличилось на 1. Просто как тот.
Увидеть, что наша чистая функция Увеличение-счетчик
Возвращает 2, но счетчик
Значение все еще то же самое. Функция возвращает увеличенное значение, не изменяя значение переменной.
Если мы будем следовать этим двум простым правилам, становится легче понять наши программы. Теперь каждая функция изолирована и не может повлиять на другие части нашей системы.
Чистые функции стабильны, последовательны и предсказуемыми. Учитывая одинаковые параметры, чистые функции всегда будут возвращать один и тот же результат. Нам не нужно думать о ситуациях, когда тот же параметр имеет разные результаты – потому что это никогда не произойдет.
Преимущества чистых функций
Код определенно проще проверить. Нам не нужно ничего поднимать. Таким образом, мы можем установить тестовые чистые функции с различными контекстами:
- Учитывая параметр
А
→ Ожидайте, что функция возвращать значениеB
- Учитывая параметр
C
→ Ожидайте, что функция возвращать значениеD
Простой пример будет функцией для получения набора номеров и ожидает, что он увеличивает каждый элемент этой коллекции.
Мы получаем Числа
Коллекция, использование карта
с Inc
Функция для увеличения каждого номера и вернуть новый список увеличенных чисел.
Для вход
[1 2 3 4 5]
ожидаемый вывод
будет [2 3 4 5 6]
.
Неподумность
Когда данные неизменяются, его Государство не может изменить После его создания. Если вы хотите изменить неизменный объект, вы не можете. Вместо этого Вы создаете новый объект с новым значением.
В JavaScript мы обычно используем для
петля. Это следующее для
Заявление имеет некоторые мусорные переменные.
Для каждой итерации мы меняем i
а также SumOfValue.
штат . Но как мы обращаемся к врачу в итерации? Рекурсия! Вернуться к Clojure!
Так что здесь у нас есть сумма
Функция, которая получает вектор численных значений. Рекомендация
прыгает обратно в петли
Пока мы не получим вектор пустым ( наша рекурсия Базовый случай
). Для каждой «итерации» мы добавим значение для Всего
Аккумулятор.
С рекурсией мы держим наш Переменные неизменный.
Наблюдение : Да! Мы можем использовать Уменьшить
Для реализации этой функции. Мы увидим это в Функции высшего порядка
тема.
Также очень часто распространяется финал Государство объекта. Представьте, что у нас есть строка, и мы хотим преобразовать эту строку в URL Slug
Отказ
В Оопе в Руби, мы бы создали класс, скажем, URLSugfify
Отказ И этот класс будет иметь Проблемы!
Способ преобразования ввода строки в URL Slug
Отказ
Красивый! Это реализовано! Здесь мы имеем обязательное программирование, которое именно мы хотим сделать в каждом проще говоря
Процесс – первый нижний регистр, затем удалить бесполезные белые пробелы и, наконец, заменить оставшиеся белые пробелы с дефисами.
Но мы мутируем входное состояние в этом процессе.
Мы можем обрабатывать эту мутацию, выполняя функциональную композицию или цепочку функций. Другими словами, результат функции будет использоваться в качестве входа для следующей функции, без изменения исходной входной строки.
Здесь у нас есть:
Обрезать
: удаляет пробел из обоих концов строкистрочные буквы
: преобразует строку на все строчные буквызаменить
: заменяет все экземпляры совпадения с заменой в данной строке
Мы объединяем все три функции, и мы можем "Slugify"
Наша строка.
Говоря о Объединение функций мы можем использовать комп
Функция для создания всех трех функций. Давайте взглянем:
Ссылочная прозрачность
Давайте реализовать Функция квадрата
:
Эта (чистая) функция всегда будет иметь одинаковый выход, учитывая тот же вход.
Прохождение “2” в качестве параметра Функция квадрата
всегда будет возвращаться 4. Так что теперь мы можем заменить (Квадрат 2)
с 4. Вот и все! Наша функция это переданный прозрачный
Отказ
В основном, если функция последовательно дает тот же результат для одного и того же входа, он является референтно прозрачным.
Чистые функции + неизменная прозрачность
С этой концепцией классная вещь, которую мы можем сделать, это восполнить функцию. Представьте, что у нас есть эта функция:
(+ 5 8)
равен 13
Отказ Эта функция всегда будет привести к 13
Отказ Таким образом, мы можем сделать это:
И это выражение всегда приведет к 16
Отказ Мы можем заменить все выражение с помощью численной постоянной и Memoize Это.
Функционирует как первоклассные объекты
Идея функций в качестве первоклассных объектов является то, что функции являются Также рассматривается как значения и используется в качестве данных.
В Clojure часто используют Defn
Чтобы определить функции, но это просто синтаксический сахар для (Def Foo (Fn ...))
. FN
Возвращает саму функцию. Defn
Возвращает var
который указывает на объект функции.
Функции в качестве первоклассных объектов могут:
- Обратитесь к этому из констант и переменных
- пропустите его как параметр другим функциям
- вернуть его в результате других функций
Идея состоит в том, чтобы лечить функции как значения и передавать функции, такие как данные. Таким образом, мы можем объединить различные функции для создания новых функций с новым поведением.
Представьте, что у нас есть функция, которая суммирует два значения, а затем удваивает значение. Что-то вроде этого:
Теперь функция, которая вычитает значения и возвращает двойной:
Эти функции имеют аналогичную логику, но разница в функциях операторов. Если мы сможем лечить функции в качестве значений и передавать их аргументами, мы можем создать функцию, которая принимает функцию оператора и использовать ее внутри нашей функции. Давайте построим это!
Выполнено! Теперь у нас есть F
аргумент и используйте его для обработки А
и преступность
. Мы прошли +
и -
Функции для составляющих с Двойной оператор
функция и создать новое поведение.
Функции высшего порядка
Когда мы говорим о функциях более высокого порядка, мы имеем в виду функцию, которая либо:
- принимает один или несколько функций в качестве аргументов или
- Возвращает функцию в качестве результата
Двойной оператор
Функция, которую мы реализовали выше, – это функция более высокого порядка, потому что она принимает функцию оператора в качестве аргумента и использует его.
Вы, наверное, уже слышали о Фильтр
, карта
и Уменьшить
Отказ Давайте посмотрим на них.
Фильтр
Учитывая коллекцию, мы хотим фильтровать по атрибуту. Функция фильтра ожидает A правда
или ложь
Значение, чтобы определить, если элемент должен или не должен быть включены в коллекцию результата. В основном, если выражение обратного вызова это правда
Функция фильтра будет включать элемент в коллекции результата. В противном случае это не будет.
Простой пример, когда у нас есть коллекция целых чисел, и мы хотим только четные номера.
Императивный подход
Императивный способ сделать это с JavaScript – это:
- Создать пустой вектор
четные числа
- Итерация за
Числа
вектор - Нажмите даже номера для
Уважение
вектор
Мы можем использовать Фильтр
Функция более высокого порядка, чтобы получить даже?
Функция и вернуть список четных чисел:
Одна интересная проблема, которую я решил на Хакерский ранг FP. Путь был Проблема массива фильтра Отказ Проблема идеи состоит в том, чтобы отфильтровывать данный массив целых чисел и выводить только те значения, которые меньше указанного значения X
.
Императивное решение для JavaScript к этой проблеме является чем-то вроде:
Мы точно говорим, что нужно сделать нашу функцию – итерации за коллекцию, сравните текущий элемент сбора с х
и нажмите этот элемент к Регистрация
Если это пройдет условие.
Декларативный подход
Но мы хотим более декларативный способ решить эту проблему и использовать Фильтр
Функция более высокого порядка.
Декларативное решение Clojure было бы чем-то вроде этого:
Этот синтаксис кажется немного странным в первую очередь, но легко понять.
# (> x
%) – это просто анонимная функция, которую получают е
S X и сравнивает его с каждым элементом в коллекции n
. % представляет собой параметр анонимной функции – в этом случае текущий элемент внутри T Он подал
территория
Мы также можем сделать это с картами. Представьте, что у нас есть карта людей со своими имя
и возраст
. И мы хотим фильтровать только людей в течение определенного значения возраста, в этом примере людей более 21 года.
Сводка кода:
- У нас есть список людей (с
имя
ивозраст
). - У нас есть анонимная функция
# (<21 (: возраст
%)). Помните, что тH
E% представляет текущий элемент из коллекции? Ну, элемент коллекции – карта людей. Если мыДелать (: Возраст {: name "Tk": Возраст 2
6}), он возвращает возраст Valuе,
26 В этом случае. - Мы фильтруем всех людей на основе этой анонимной функции.
карта
Идея карты состоит в том, чтобы преобразовать коллекцию.
Давайте получим то же самое люди
Коллекция выше. Мы не хотим фильтровать «чрезмерным возрастом» сейчас. Мы просто хотим список строк, что-то вроде TK 26 лет
Отказ Так что окончательная строка может быть : Имя: возраст лет
где : Имя
и : возраст
атрибуты из каждого элемента в люди
коллекция.
В обязательном состоянии JavaScript это было бы:
В декларативном уровне Clojure это было бы:
Вся идея состоит в том, чтобы преобразовать данную коллекцию в новую коллекцию.
Еще один интересный рейтинг хакера был Обновить список проблем Отказ Мы просто хотим обновить значения данной коллекции со своими абсолютными значениями.
Например, вход [1 2 3 -4 5]
нужен выход, чтобы быть [1 2 3 4 5]
. Абсолютное значение -4
это 4
Отказ
Простое решение было бы обновлением на месте для каждого значения коллекции.
Мы используем Math.abs
Функция для преобразования значения в его абсолютное значение и выполнить обновление на месте.
Это не Функциональный способ реализации этого решения.
Во-первых, мы узнали о неизменности. Мы знаем, насколько важна неизменность, чтобы сделать наши функции более последовательными и предсказуемыми. Идея состоит в том, чтобы создать новую коллекцию со всеми абсолютными значениями.
Во-вторых, почему бы не использовать карта
Здесь, чтобы «преобразовать» все данные?
Моя первая идея должна была построить до абсолютного
Функция для обработки только одного значения.
Если он негатив, мы хотим преобразовать его в положительном значение (абсолютное значение). В противном случае нам не нужно его трансформировать.
Теперь, когда мы знаем, как сделать Абсолют
Для одного значения мы можем использовать эту функцию для пропускания в качестве аргумента для карта
функция. Ты помнишь, что Функция высшего порядка
может получить функцию как аргумент и использовать его? Да, карта может сделать это!
Вот это да. Так прекрасно! ?
Уменьшать
Идея уменьшения состоит в том, чтобы получить функцию и коллекцию и вернуть значение, созданное путем объединения элементов.
Общим примером, о которых люди говорят, – это получить общую сумму заказа. Представьте, что вы были на сайте покупок. Вы добавили Продукт 1
, Продукт 2
, Продукт 3
и Продукт 4
в вашу корзину (заказ). Теперь мы хотим рассчитать общий объем корзины.
При императивном способе мы бы переписываем список заказов и суммируйте сумму каждой суммы продукта на общую сумму.
Использование Уменьшить
мы можем построить функцию для обработки сумма суммы
и пропустите его как аргумент для Уменьшить
функция.
Здесь у нас есть корзина
, функция сумма сумма
это получает текущий Общая сумма
и Текущий продукт
объект к сумма
их.
Получить общее количество
Функция используется для Уменьшить
корзина
Используя сумма сумма
и начать с 0
Отказ
Другой способ получить общую сумму составлять карта
и Уменьшить
Отказ Что я имею в виду под этим? Мы можем использовать карта
трансформировать корзина
в коллекцию сумма
Значения, а затем просто используйте Уменьшить
Функция с +
функция.
получить сумму
Получает объект продукта и возвращает только сумма
ценить. Так что же мы имеем здесь [10 30 20 60]
. А потом Уменьшить
Сочетает в себе все предметы, добавляя вверх. Красивый!
Мы посмотрели на то, как работает каждый функция высшего порядка. Я хочу показать вам пример того, как мы можем составить все три функции в простом примере.
Говорить о Корзина
Представьте, что у нас есть этот список продуктов в нашем порядке:
Мы хотим общую сумму всех книг в нашей корзине. Просто как тот. Алгоритм?
- Фильтр по типу книги
- Превратите корзину в коллекцию суммы, используя карта
- Объедините все предметы, добавив их с уменьшать
Выполнено! ?
Ресурсы
Я организовал некоторые ресурсы, которые я прочитал и изучал. Я делюсь теми, которые я нашел действительно интересным. Для большего количества ресурсов посетите мой Функциональное программирование GitHub Repository Отказ
Интрас
- Изучение FP в JS
- INTRO DO FP с Python
- Обзор ФП
- Быстрое введение в функциональные JS
- Что такое FP?
- Функциональный программирующий жаргон
Чистые функции
- Что такое чистая функция?
- Чистое функциональное программирование 1
- Чистое функциональное программирование 2
Неизменные данные
- Неизменные DS для функционального программирования
- Почему общий муравьего государства является корнем всего зла
- Структурное разделение в Clojure: Часть 1
- Структурное разделение в Clojure: часть 2
- Структурное разделение в Clojure: часть 3
- Структурное разделение в Clojure: Финальная часть
Функции высшего порядка
- Красноречивый JS: функции высшего порядка
- Fun Fun Function Find Filter
- Fun Fun Function Map
- Fun Fun Function Основное уменьшение
- Fun Fun Function Advanced Уменьшить
- Функции более высокого порядка Clojure
- Чисто функциональный фильтр
- Чисто функциональная карта
- Чисто функционал уменьшить
Декларативное программирование
Вот и все!
Эй, люди, я надеюсь, что вы весело прочитали этот пост, и я надеюсь, что вы многое узнали здесь! Это была моя попытка поделиться тем, что я учусь.
Вот репозиторий со всеми кодами Из этой статьи.
Приди учишься со мной. Я разделяю ресурсы и мой код в этом Обучение функционального программирования хранилища Отказ
Я надеюсь, вы увидели что-то полезное для вас здесь. И увидимся в следующий раз!:)
Тк
Оригинал: “https://www.freecodecamp.org/news/an-introduction-to-the-basic-principles-of-functional-programming-a2c2a15c84/”