ноль, предисловие
Когда дело доходит до функционального программирования, вы, должно быть, слышали о нем более или менее, но вы можете не иметь ясного представления о значении и сути функционального программирования.
Поэтому в этой статье мы надеемся поделиться идеями и практиками, связанными с функциональным программированием (на примере JavaScript), с прикладной (а не академической) точки зрения для инженеров.
На самом деле содержание статьи в основном исходит из реорганизации после прочтения различных ссылок ниже, поэтому, если есть какая-либо ошибка, я надеюсь, что каждый может помочь ее исправить ~
1. Что такое функциональное программирование?
Functional programming is a programming paradigm
1.treats computation as the evaluation of mathematical functions
2.avoids changing-state and mutable data
by wikipedia
Из приведенного выше определения Википедии есть три основных момента.
-
Programming Paradigm
: парадигма программирования -
Mathematical Functions
: математическая функция -
Changing-state And Mutable Data
: изменить состояние и изменяемые данные
Отдельно анализируются следующие моменты.
1.1 Что такое парадигма программирования?
Парадигма программирования концептуально относится к основным стилям и парадигматическим шаблонам программирования.
Другими словами, это понимание программистом того, как использовать программирование для решения проблем.Мировой прогноз и методология.
Если язык программирования уподобить оружию, а его синтаксис, инструменты и навыки — уловкам, то принятая им парадигма программирования — это также ментальный метод внутренней силы.
Парадигма может быть реализована на разных языках, и язык может поддерживать несколько парадигм одновременно. Например, JavaScript — мультипарадигмальный язык.
1.2 Что такое математическая функция?
Как правило, в процессе изменения предположим, что есть две переменные х и у. Если существует уникальный у, соответствующий любому х, то х является независимой переменной, а у является функцией от х. Диапазон значений x называется доменом функции, а диапазон значений соответствующего y называется доменом функции.
Приведенные выше определения, в математике младших классов средней школы, мы все должны выучить...
Другими словами, функция — это просто отношение между двумя типами значений: входными и выходными.
Хотя каждый вход имеет только один выход, разные входы могут иметь один и тот же выход. На рисунке ниже показано правильное функциональное соотношение от x до y;
Напротив, на приведенном ниже графике не показана функциональная связь, поскольку входное значение 5 указывает на несколько выходов:
1.2.1 Что такое чистые функции?
Чистая функция — это функция, которая при одних и тех же входных данных всегда получает один и тот же результат без каких-либо наблюдаемых побочных эффектов.
По определению видно, что чистая функция на самом деле является математической функцией, то есть отображением входных параметров в выходные результаты.
Чистые функции без побочных эффектов, очевидно, ссылочно прозрачны.
Ссылочная прозрачность означает, что часть кода может быть заменена результатом его выполнения без изменения поведения всей программы.
const double = x => x * 2
const addFive = x => x + 5
const num = double(addFive(10))
num === double(10 + 5)
=== double(15)
=== 15 * 2
=== 30
Но после долгого разговора, каковы побочные эффекты...?
1.2.2 Что такое побочные эффекты?
Побочный эффект — это изменение состояния системы во время вычислений или наблюдаемое взаимодействие с внешним миром.
Побочные эффекты могут включать, помимо прочего, следующие действия:
- изменить файловую систему
- вставить запись в базу
- отправить http запрос
- изменить данные
- журнал печати
- Получить пользовательский ввод
- DOM-запрос
- статус системы доступа
- ...
Любое взаимодействие со средой вне функции является побочным эффектом — это может заставить вас усомниться в жизнеспособности программирования без побочных эффектов.
Философия функционального программирования предполагает, что побочные эффекты являются основной причиной плохого поведения.
Конечно, это не означает, что все побочные эффекты должны быть запрещены, но что их следует допускать в пределах контролируемого диапазона.
Мы узнаем, как ими управлять, позже, когда будем говорить о функторах и монадах.
1.2.3 Каковы преимущества чистых функций~~ (кто сказал, что это правильно, дайте ему)~~?
Проблема с объектно-ориентированными языками заключается в том, что они всегда несут с собой эти неявные среды. Все, что вам нужно, это банан, но вы получите гориллу с бананом ... и целые джунгли
Erlang Джо Армстронг
Таким образом, использование чистых функций будет иметь следующие преимущества:
- Кэшируемый
- Портативный/самодокументирующийся
- Тестируемый
- Разумный
- Параллельный код
1.3 Почему следует избегать изменения состояния и изменяемых данных?
Shared mutable state is the root of all evil
Общее изменяемое состояние — корень всех зол
by Pete Hunt
const obj = { val: 1 }
someFn(obj)
console.log(obj) // ???
from Building Scalable, Highly Concurrent & Fault Tolerant Systems - Lessons Learned
1.4. Фундаментальная функциональность или умеренная функциональность?
Когда дело доходит до функциональных языков программирования, вашей первой реакцией может быть Haskell, OCaml, Lisp, Erlang, Scala, F#…
Потому что они могут иметь следующие свойства:
- Функции "первого класса"
- неизменяемые данные
- Используйте рекурсию вместо циклов
- карри
- ленивая оценка
- Алгебраические типы данных
- сопоставление с образцом
- ...
Когда дело доходит до JavaScript, многие сначала могут подумать, что это объектно-ориентированный язык.
Но подумайте о том, что я сказал ранее: функциональное программирование — это просто парадигма программирования, а парадигмы программирования подобны «внутренним навыкам», поэтому они не полностью связаны с перечисленными выше языковыми возможностями, но связаны с вашим собственным программным мышлением (т.е. мировоззрением и методология) более актуальна.
С функциональной стороны, поскольку JavaScript поддерживает такие функции, как функции высшего порядка, анонимные функции, функции-граждане первого класса, замыкания, деструктурирование (сопоставление с образцом) и т. д., он также может поддерживать парадигму функционального программирования. (Хоть он и не так принципиально функционален, в принципе достаточно ~ особенно новых фич вроде стрелочных функций в ES6 ~ и различных библиотек классов)
Фактически, JavaScript основан на прототипах.Мультипараметриксязык.
1.5.Что не так с JavaScript как с функциональным языком?
1.5.1 Неизменяемые структуры данных
JavaScript имеет в общей сложности 6 примитивных типов (включая недавно добавленный тип Symbol в ES6): Boolean, Null, Undefined, Number, String и Symbol. За исключением этих примитивных типов, все остальные типы являются объектами, а объекты изменяемы.
1.5.2 Ленивая оценка
Ленивый означает, что процесс оценки не происходит немедленно.
Например, для некоторых математических задач нам может не понадобиться вычислять все выражения в начале, чтобы некоторые выражения можно было исключить в процессе вычислений.
Ленивая оценка связана с ранней оценкой.
Например, в большинстве языков сначала оцениваются выражения в параметрах, что также известно какзаявлениеязык.
Например, посмотрите на следующееJavaScript
Функция:
wholeNameOf(getFirstName(), getLastName())
getFirstName
а такжеgetLastName
будет выполняться последовательно, а возвращаемое значение будет такимwholeNameOf
параметры функции,wholeNameOf
Функция вызывается последней.
Кроме того, для операций с массивами в большинстве языков также используются прикладные программы.
[1, 2, 3, 4].map(x => x + 1)
Итак, это выражение сразу возвращает результат [2, 3, 4, 5].
Конечно это не значитJavaScript
Есть проблема с применением языка, но нет поддержки ленивых последовательностей.JavaScript
неправильно. еслиmap
После большого массива мы обнаружили, что, когда нам действительно нужны только первые 10 элементов, вычислять все элементы избыточно.
1.5.3 Состав функций
Объектная ориентация часто сравнивается с существительным, а функциональное программирование — с глаголом. Объектно-ориентированная абстракция — это объект, а описание объекта — это, естественно, существительное.
Объектно-ориентированный инкапсулирует все операции и данные в объекты и выполняет соответствующие операции, получая сообщения. Например, объекты Китти, они могут принять сообщение «привет», а затем действовать соответственно.
Функциональная абстракция противоположным образом заключается в абстрагировании действия, например, «привет» — это функция, а параметры функции по мере того, как данные передаются Китти (т. е. Китти входит в функцию «привет», это должен быть «Привет Китти»).
Объектно-ориентированный может разделять некоторые поведения или атрибуты между объектами и комбинациями, функциональные идеи черезкомбинацияСуществующая функция формирует новую функцию.
Однако, несмотря на то, что язык JavaScript поддерживает функции более высокого порядка, не существует встроенного способа объединения функций для создания новых функций. Однако эти мощные комбинации функций часто затмеваются светом библиотек инструментов, таких как Underscore и Lodash (проблемы этих библиотек будут обсуждаться позже).
1.5.4 Оптимизация хвостовой рекурсии
В функциональных языках программирования нет возможности реализовать циклы из-за неизменяемых структур данных. Таким образом, все циклы реализуются рекурсией.
Однако неправильное использование рекурсии может привести к переполнению стека (Stack Overflow), поэтому хвостовая рекурсия обычно используется для оптимизации.
Хотя спецификация оптимизации хвостовой рекурсии указана в спецификации ES6, существует очень мало интерпретаторов, обеспечивающих реализацию.эта ссылка
1.5.5 Алгебраическая система типов
Как язык со слабой типизацией, JavaScript не имеет статической системы типов. Однако в качестве дополнения можно использовать некоторые предварительно скомпилированные языки, такие как TypeScript~
2. Декларативный и императивный
Декларативный VS Императивный, разница между ними просто Что VS Как.
2.1 Разница в «идеологии»~
Декларативный:
- Программа абстрагирует процесс управления потоком, а код описывает — поток данных: то есть, что делать.
- Более зависимые выражения.
Выражение — это небольшой фрагмент кода, который вычисляет значение. Выражение обычно представляет собой композицию вызова некоторой функции, некоторого значения и оператора, вычисляющего результирующее значение.
императив:
- Код описывает конкретные шаги, используемые для достижения желаемого результата - поток управления: то есть, как это сделать.
- Заявления используются часто.
Оператор — это небольшой фрагмент кода, который выполняет определенное действие. Общие примеры операторов включают for, if, switch, throw и т. д.
2.2. Подарите каштаны 🌰...
Пример 1: Хотите получить сумму квадратов всех данных в массиве
// 命令式
function mysteryFn (nums) {
let squares = []
let sum = 0 // 1. 创建中间变量
for (let i = 0; i < nums.length; i++) {
squares.push(nums[i] * nums[i]) // 2. 循环计算平方
}
for (let i = 0; i < squares.length; i++) {
sum += squares[i] // 3. 循环累加
}
return sum
}
// 以上代码都是 how 而不是 what...
// 函数式
const mysteryFn = (nums) => nums
.map(x => x * x) // a. 平方
.reduce((acc, cur) => acc + cur, 0) // b. 累加
Пример 2: Хотите получить среднее значение половины всех четных значений в массиве
// 命令式
function mysteryFn(nums) {
let sum = 0
let tally = 0 // 1. 创建中间变量
for (let i = 0; i < nums.length; i++) {
if (nums[i] % 2 === 0) { // 2. 循环,值为偶数时累加该值的一半并记录数量
sum += nums[i] / 2
tally++
}
}
return tally === 0 ? 0 : sum / tally // 3. 返回平均值
}
// 函数式
const mysteryFn = (nums) => nums
.filter(x => x % 2 === 0) // a. 过滤非偶数
.map(x => x / 2) // b. 折半
.reduce((acc, cur, idx, { length }) => (
idx < length - 1
? acc + cur // c. 累加
: (acc + cur) / length // d. 计算平均值
), 0)
использованная литература
- Руководство по функциональному программированию JS
- Руководство по стилю бесточечного программирования
- Hey Underscore, You're Doing It Wrong!
- Functional Concepts with JavaScript: Part I
- Professor Frisby Introduces Composable Functional JavaScript
- Введение в функциональное программирование
Статьи по Теме
- Функциональное программирование JavaScript (1) -- эта статья
- Функциональное программирование JavaScript (2)
- Функциональное программирование JavaScript (3)
- Функциональное программирование JavaScript (4) назревает...
выше продолжение следует...