Функциональное программирование против декларативного программирования против императивного программирования
Я слишком привык к императивному программированию, которое является обычным способом заставить компьютер выполнять пошаговую процедуру, чтобы получить конечный результат. С другой стороны, декларативное программирование просто пропускает входные данные и ожидает выходных данных без указания процедуры, как это делается. Я запутался в функциональном программировании. Я знаю, что функциональное программирование - это парадигма программирования, которая рассматривает вычисления как оценку математических функций, избегает состояния и изменчивых данных и не является типом декларативного языка. Тем не менее, я до сих пор не могу понять, как это может работать.
Давайте рассмотрим пример выполнения чисел Фибоначчи.
Императивное программирование:
#include<stdio.h>
#include<conio.h>
main()
{
int n,i,c,a=0,b=1;
printf("Enter Fibonacci series of nth term : ");
scanf("%d",&n);
printf("%d %d ",a,b);
for(i=0;i<=(n-3);i++)
{
c=a+b;
a=b;
b=c;
}
printf("%d ",c);
getch();
}
Декларативное программирование:
Give the nth number and it will return the value of the nth number
Как работает функциональная программа?
Плюс поправьте меня, если мои определения неверны. Пожалуйста, не стесняйтесь комментировать..
7 ответов
Ваш пример декларативного программирования выше не является реальной программой, так что это не хороший пример.
Основное различие между императивом и декларативом. Функциональный - это особый вид декларативного.
C, C++, Java, Javascript, BASIC, Python, Ruby и большинство других языков программирования являются обязательными. Как правило, если он имеет явные циклы (для, в то время как, повтор), которые изменяют переменные с явными операциями присваивания в каждом цикле, то это обязательно.
SQL и XSLT являются двумя хорошо известными примерами декларативного программирования. Языки разметки, такие как HTML и CSS, также являются декларативными, хотя обычно они недостаточно мощны для описания произвольных алгоритмов.
Вот пример вычисления (суммирование дохода по полу из подходящего источника данных), сначала написанного на императивном языке (Javascript), а затем на декларативном языке (SQL).
Императивное программирование
var income_m = 0, income_f = 0;
for (var i = 0; i < income_list.length; i++) {
if (income_list[i].gender == 'M')
income_m += income_list[i].income;
else
income_f += income_list[i].income;
}
Обратите внимание:
- явная инициализация переменных, которые будут содержать промежуточные суммы;
- явный цикл по данным, изменение управляющей переменной (
i
) и промежуточные итоги на каждой итерации; - условия (
if
s) используются только для выбора пути к коду на каждой итерации.
Декларативное программирование
select gender, sum(income)
from income_list
group by gender;
Обратите внимание:
- Ячейки памяти, содержащие текущие итоги, подразумеваются выводом, который вы объявляете нужным;
- любой цикл, который ЦП должен будет выполнить (например, над таблицей come_list), подразумевается выводом, который вы объявляете нужным, и структурой исходных данных;
- условные
case
в SQL) функционально используются для указания желаемого выходного значения на основе входных значений, а не для выбора пути к коду.
Функциональное программирование
Как я уже упоминал выше, SQL case
является отличным примером функционального способа программирования, который является ограниченным подмножеством декларативного программирования, в котором заданные вычисления задаются путем составления функций.
Функции - это вещи, которые принимают входные и выходные данные (например, case
, sum()
...)
Композиция означает объединение двух или более элементов путем указания того, как выходные данные одного из них передаются в качестве входных данных другому (как правило, путем записи одного из другого.) Наконец, вся композиция, которая сама по себе является большой функцией, применяется к доступным входы, чтобы получить желаемый результат.
В этом фрагменте я объявляю вывод, который я хочу, составляя функции sum()
а также case
, Это называется функциональным программированием:
select
sum(case when some_flag = 'X' then some_column
else some_other_column end)
from
...
Если композиция из двух или более функций и их применение к входным данным являются единственными конструкциями, доступными в данном языке, этот язык называется чисто функциональным. В этих языках вы заметите полное отсутствие циклов, присваивания переменных и других типично обязательных операторов.
Редактировать: я рекомендую посмотреть некоторые из выступлений Анжаны Вакиль о функциональном программировании в Javascript, чтобы получить лучшее представление о том, что это такое.
Ошибочно упрощать утверждение, что императивное программирование отличается от декларативного программирования, ошибочно предполагая отсутствие упорядоченности в последнем.
Чистое функциональное программирование не мешает выражать порядок и реализацию, скорее, оно менее способно выражать случайный случайный порядок на уровне операционной семантики. Также у него есть преимущество "Не повторяйся" (СУХОЙ), который является формой декларативного стиля (см. Ниже).
Однако чисто функциональное программирование не гарантирует декларативную семантику высокого уровня. Для этого вам нужно применить правильное определение декларативного и императивного.
Еще одно полезное объяснение, которое я нашел в Pro XAML с C#:
На декларативном
В декларативном программировании исходный код написан таким образом, что выражает желаемый результат кода, практически не акцентируя внимание на фактической реализации.
На императиве
Императивное программирование является противоположностью декларативного программирования. Если декларативное программирование можно рассматривать как объявление желаемого результата, императивное программирование можно рассматривать как написание строк кода, которые представляют инструкции о том, как достичь желаемого результата.
Функциональное программирование - это парадигма декларативного программирования, которая представляет собой парадигму, которая выражает набор операций без раскрытия того, как они реализованы или как данные проходят через них. Императивное программирование рассматривает компьютерную программу как просто последовательность операторов сверху вниз, которые изменяют состояние системы для вычисления результата.
Вот пример императивного программирования: мы перебираем массив, вычисляем квадрат каждого элемента и сохраняем новые значения внутри того же массива. Мы мутируем массив. Кроме того, этот цикл нельзя использовать повторно, для каждого отдельного массива мы должны определить новый цикл for.
var array= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for(let i= 0; i < array.length; i++) {
array[i]=Math.pow(array[i], 2);
}
array; //-> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
В javascript я бы использовал Array.map()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map((i)=>i*i)
В этом методе мы не знаем, как реализован Array.map(). Определение программы отделено от оценки. Что еще более важно, этот код не изменяет исходный массив, он создает новый массив
Еще один хороший пример декларативного программирования - это написание SQL-запросов. Мы просто пишем простой оператор SQL для извлечения данных из базы данных, но мы не знаем, что происходит за сценой, вся магия абстрагируется от нас.
Подумайте о c фильтрах. Где вы читаете из стандартного ввода и пишите в стандартный вывод. Код может быть обязательным, но программа используется как функция. Скажем, у вас естьфункция программы, а затем добавьте к ней:
cat foo | функция | тройник
Будет отфильтровывать содержимое функции foo через, затем через тройник фильтра для записи в stdout и создания бара. Подумайте также о grep и awk, итератор в обоих подразумевается, и они используются как функции.
Идея о том, что есть декларативные языки, а есть императивные языки, является мифом.
Каждая вещь, которую вы делаете в (скажем) Java, является заявлением компилятора о намерениях относительно того, для чего вам нужен байт-код. Вам все равно, как это достигается. Но сам байт-код является декларацией JIT-компилятору того, чего вы хотите достичь с помощью машинных инструкций. Вам все равно, как это достигается.
Даже сборка не является действительно обязательной. ЦП интерпретирует машинный код и выполняет всевозможные оптимизации и преобразования. И (кроме того, что он хотел, чтобы это было очень быстро) парень, который написал сборку (люди все еще пишут сборку?), не заботится о том, что ядра AMD и ядра IBM будут выполнять машинные инструкции по-разному.
С другой стороны, каждый вызов библиотечной функции является заявлением автора библиотеки о том, чего вы хотите добиться от вызова, но вас (обычно) не волнует, как это достигается. И, в свою очередь, сам ваш код может быть использован для удовлетворения заявлений о намерениях других людей, которым не будет дела до того, как вы это сделали.
И наоборот, простые операторы SQL не могут удовлетворить сложные требования (что неудивительно). Чтобы получить то, что нужно, вы должны использовать либо множество вложенных подзапросов (если вы мазохист), либо записывать промежуточные результаты во временные таблицы и применять к ним дополнительные наборы запросов, каждый из которых может потребовать больше запросов на большем количестве временных таблиц (если вы прагматик). Эти два подхода эквивалентны. И какую бы из них вы ни взяли, она представляет собой «императивную» серию инструкций.
Действительно все декларативные средства - это "очень высокий уровень". Но чтобы получить то, что вам действительно нужно, вы должны часто опускаться на более низкий уровень. Точно так же API Java может сам эмулировать так называемый декларативный язык (database.select().from(table1, table2).where(<lambda>).groupBy(<lambda>)).having(<lambda>)
). Но когда это написано так, это уже не выглядит таким «декларативным», не так ли? Ужасно похоже, что вы связываете императивные инструкции вместе.
Этот пример демонстрирует, как можно использовать Java в качестве так называемого функционального языка. Так функционален ли SQL? Версия Java выглядит почти так же и делает то же самое. Но написано на "императивном" языке. Так обязателен ли SQL? Является ли Java функциональным? Декларативный?
Разработчики языков и защитники языков любят представлять свои языки как обладающие определенными качествами, которые делают их звучание фундаментально отличным от основных языков, как имеющие особый философский подход к решению проблем. Но обычно несколько царапин на поверхности говорят о чем-то более будничном.
Я бы не стал зацикливаться на том, что означают императивный, функциональный и декларативный. Каждый язык является декларативным, императивным и функциональным. Найдите стиль написания кода, который соответствует вашему вкусу, и используйте язык(и), которые соответствуют вашему стилю.
Процессы преобразуют входы в выходы. Компьютерные программы - это списки аппаратных операций, которые при выполнении будут выполнять эти процессы на любых входах, которые они подают. Не все компьютерные языки могут использоваться для написания программ, которые генерируют процессы. Некоторые компьютерные языки просто описывают отношения между данными, и ваш вопрос сформулирован правильно, чтобы задать вопрос о языках программирования, которые определяют процессы.
Оригинальные императивные языки, такие как Assembly, написаны в терминах машинных операций. Примитивы move-data-into-register-x, add-register-x-to-y-store-in-y
… Императивные языки описывают процессы в терминах того, как они выполняются какой-то конкретной машиной данных.
Декларативные языки (* функциональные языки являются их подмножеством) написаны в терминах не машинных примитивов. Математика - это декларативный язык, аксиомами чисел которого являются некоторые из его примитивов. Декларативные языки описывают процессы более четко, потому что они выражают преобразования в терминах исходной проблемной области.
например 1. Fib(0), Fib(1)=1, Fib(n) = n-1 + n-2
например 2. x = [x in 1..100 if x mod 3 != 0]
* Термин функциональный язык был придуман, когда программисты в основном писали машинные инструкции. Теперь концепции функциональных языков, такие как процедуры без побочных эффектов и выражения списков, стали частью основных императивных языков. Таким образом, функциональный язык мало чем отличается от декларативного языка.
Декларативные программы явно не соответствуют машинным инструкциям. Хорошими примерами чисто декларативных языков являются математика, лисп, пролог и вольфрам альфа. HTML, SQL, XSLT, SDLang - это языки, которые определяют отношения данных, они не являются языками программирования того типа, о котором вы спрашиваете. Вы не создаете компьютерные процессы с HTML, SQL, XSLT или SDLang.
В наши дни современные языки высокого уровня действительно представляют собой смесь императивных и декларативных парадигм, поскольку термины были изначально придуманы. Хорошие проекты классов высокого уровня, почти описывают, что происходит с данными через имена методов. Так что термины ИМО мало анахроничны.