В чем разница между функциональными и императивными языками программирования?
Большинство основных языков, включая языки объектно-ориентированного программирования (OOP), такие как С#, Visual Basic, С++ и Java, были разработаны, чтобы в первую очередь поддерживать императивное (процедурное) программирование, тогда как языки Haskell/gofer, как и все, являются функциональными. Может ли кто-нибудь уточнить, в чем разница между этими двумя способами программирования?
Я знаю, что это зависит от требований пользователя, чтобы выбрать способ программирования, но почему рекомендуется изучать языки функционального программирования?
Ответы
Ответ 1
Определение:
Императивный язык использует последовательность заявлений, чтобы определить, как достичь определенной цели. Говорят, что эти утверждения изменяют состояние программы, поскольку каждый из них выполняется по очереди.
<сильные > Примеры:
Java является обязательным языком. Например, можно создать программу для добавления серии чисел:
int total = 0;
int number1 = 5;
int number2 = 10;
int number3 = 15;
total = number1 + number2 + number3;
Каждый оператор изменяет состояние программы, присваивая значения каждой переменной окончательному добавлению этих значений. Используя последовательность из пяти операторов, программа явно сообщает, как добавить числа 5, 10 и 15 вместе.
Функциональные языки:
Парадигма функционального программирования была явно создана для поддержки чисто функционального подхода к решению проблем. Функциональное программирование является формой декларативного программирования.
Преимущества чистых функций:
Основной причиной реализации функциональных преобразований как чистых функций является то, что чистые функции являются составными: то есть автономными и безгосударственными. Эти характеристики приносят ряд преимуществ, в том числе следующие:
Повышенная читаемость и ремонтопригодность. Это связано с тем, что каждая функция предназначена для выполнения конкретной задачи с учетом ее аргументов. Функция не полагается на какое-либо внешнее состояние.
Простое повторное развитие. Поскольку код проще реорганизовать, изменения в дизайне часто проще реализовать. Например, предположим, что вы пишете сложное преобразование, а затем понимаете, что некоторый код повторяется несколько раз в преобразовании. Если вы реорганизуете чистый метод, вы можете называть свой чистый метод по своему усмотрению, не беспокоясь о побочных эффектах.
Более легкое тестирование и отладка. Поскольку чистые функции могут быть легко протестированы изолированно, вы можете написать тестовый код, который вызывает чистую функцию с типичными значениями, допустимыми крайними случаями и недопустимыми случаями краев.
Для людей ООП или
Императивные языки:
Объектно-ориентированные языки хороши, когда у вас есть фиксированный набор операций над вещами, и по мере развития вашего кода вы в первую очередь добавляете новые вещи. Это может быть достигнуто путем добавления новых классов, которые реализуют существующие методы, а существующие классы остаются в силе.
Функциональные языки хороши, когда у вас есть фиксированный набор вещей, и по мере развития вашего кода вы в первую очередь добавляете новые операции над существующими вещами. Это может быть достигнуто путем добавления новых функций, которые вычисляются с использованием существующих типов данных, и существующие функции остаются в силе.
Минусы:
Это зависит от требований пользователя, чтобы выбрать способ программирования, поэтому есть вред только тогда, когда пользователи не выбирают правильный путь.
Когда эволюция идет не так, у вас есть проблемы:
- Добавление новой операции в объектно-ориентированную программу может потребовать редактирования многих определений классов для добавления нового метода
- Добавление нового типа вещи в функциональную программу может потребовать редактирования многих определений функций для добавления нового случая.
Ответ 2
Вот разница:
Императив:
- Начало
- Включите размер обуви 9 1/2.
- Сделайте место в кармане, чтобы сохранить массив [7] ключей.
- Поместите ключи в комнату для ключей в кармане.
- Введите гараж.
- Открыть гараж.
- Введите автомобиль.
... и т.д. и далее...
- Поместите молоко в холодильник.
- Стоп.
Декларативный, функционал которого является подкатегорией:
- Молоко - здоровый напиток, если у вас нет проблем с перевариванием лактозы.
- Обычно, один хранит молоко в холодильнике.
- Рефрижератор - это коробка, которая держит вещи в ней прохладно.
- Магазин - это место, где продаются предметы.
- Под "продажей" мы подразумеваем обмен вещами на деньги.
- Кроме того, обмен денег на вещи называется "покупка".
... и т.д. и далее...
- Удостоверьтесь, что у нас есть молоко в холодильнике (когда нам это нужно - для ленивых функциональных языков).
Резюме. На императивных языках вы говорите компьютеру, как изменять биты, байты и слова в нем и в каком порядке. В функциональных, мы говорим компьютеру, что такое вещи, действия и т.д. Например, мы говорим, что факториал 0 равен 1, а факториал любого другого натурального числа является произведением этого числа и факториала его предшественника. Мы не говорим: для вычисления факториала n зарезервируйте область памяти и сохраните там 1, затем умножьте число в этой области памяти с номерами от 2 до n и сохраните результат в одном месте и в конце, область памяти будет содержать факториал.
Ответ 3
Большинство современных языков в той или иной степени являются как императивными, так и функциональными, но для лучшего понимания функционального программирования лучше всего взять пример чистого функционального языка, такого как Haskell, в отличие от императивного кода на не очень функциональном языке, таком как java/С#. Я считаю, что это всегда легко объяснить на примере, поэтому ниже один.
Функциональное программирование: вычислить факториал из n, т.е. n! то есть nx (n-1) x (n-2) x... x 2 X 1
-- | Haskell comment goes like
-- | below 2 lines is code to calculate factorial and 3rd is it execution
factorial 0 = 1
factorial n = n * factorial (n - 1)
factorial 3
-- | for brevity let call factorial as f; And x => y shows order execution left to right
-- | above executes as := f(3) as 3 x f(2) => f(2) as 2 x f(1) => f(1) as 1 x f(0) => f(0) as 1
-- | 3 x (2 x (1 x (1)) = 6
Обратите внимание, что Haskel допускает перегрузку функции до уровня значения аргумента. Теперь ниже приведен пример императивного кода в возрастающей степени императивности:
//somewhat functional way
function factorial(n) {
if(n < 1) {
return 1;
}
return n * factorial(n-1);
}
factorial(3);
//somewhat more imperative way
function imperativeFactor(n) {
int f = 1
for(int i = 1; i <= n; i++) {
f = f * i
}
return f;
}
Это чтение может быть хорошим справочным материалом для понимания того, как императивный код больше фокусируется на том, как часть, состояние машины (я в цикле), порядке выполнения, управлении потоком.
Более поздний пример можно рассматривать примерно как код java/С# lang, а первую часть - как ограничение самого языка в отличие от Haskell для перегрузки функции на значение (ноль), и, следовательно, можно сказать, что это не пуристический функциональный язык, с другой Со стороны можно сказать, что он поддерживает функциональную прогу. в некоторой степени.
Раскрытие: ни один из приведенных выше кодов не протестирован/выполнен, но, надеюсь, должен быть достаточно хорош, чтобы передать концепцию; Также я был бы признателен за комментарии для любой такой коррекции :)
Ответ 4
Функциональное программирование - это форма декларативного программирования, которая описывает логику вычислений, и порядок выполнения полностью не подчеркивается.
Проблема: я хочу превратить это существо из лошади в жирафа.
- Удлинить шею
- Удлинить ноги
- Применить пятна
- Дайте существу черный язык
- Удалить конский хвост
Каждый элемент может быть запущен в любом порядке для получения одинакового результата.
Императивное программирование носит процедурный характер. Государство и порядок важны.
Проблема: я хочу оставить свою машину.
- Обратите внимание на начальное состояние ворот гаража
- Остановить машину на дороге
- Если дверь гаража закрыта, откройте дверь гаража, запомните новое состояние; в противном случае продолжить
- Вытащить машину в гараж
- Закрыть гаражные ворота
Каждый шаг должен быть сделан, чтобы достичь желаемого результата. Вытягивание в гараж, когда дверь гаража закрыта, приведет к поломке двери гаража.
Ответ 5
Функциональное программирование - это "программирование с функциями", где функция имеет некоторые ожидаемые математические свойства, включая ссылочную прозрачность. Из этих свойств вытекают дополнительные свойства, в частности, знакомые этапы рассуждений, обеспечиваемые замещаемостью, которые приводят к математическим доказательствам (т.е. Оправдывают уверенность в результате).
Отсюда следует, что функциональная программа является просто выражением.
Вы можете легко увидеть контраст между двумя стилями, отметив места в императивной программе, где выражение больше не является ссылочно прозрачным (и поэтому не построено с функциями и значениями и не может само быть частью функции). Два наиболее очевидных места:
мутация (например, переменные)
другие побочные эффекты
нелокальный поток управления (например, исключения)
В этой структуре программ-выражений, которые состоят из функций и значений, построена целая практическая парадигма языков, понятий, "функциональных шаблонов", комбинаторов и систем различного типа и алгоритмов оценки.
По самому крайнему определению почти любой язык, даже C или Java, можно назвать функциональным, но обычно люди резервируют термин для языков с соответствующими абстракциями (такими как замыкания, неизменные значения и синтаксические средства, такие как сопоставление шаблонов),
Что касается использования функционального программирования, то это связано с использованием функцинов и сбором кода без каких-либо побочных эффектов.
используется для записи доказательств
Ответ 6
Императивный стиль программирования практиковался в веб-разработке с 2005 года вплоть до 2013 года.
С императивным программированием мы выписали код, который перечислял, что именно должно делать наше приложение, шаг за шагом.
Стиль функционального программирования создает абстракцию с помощью умных способов объединения функций.
В ответах упоминается декларативное программирование, и в связи с этим я скажу, что декларативное программирование перечисляет некоторые правила, которым мы должны следовать. Затем мы предоставляем то, что мы называем некоторым начальным состоянием нашего приложения, и мы позволяем этим правилам как бы определять поведение приложения.
Теперь, эти быстрые описания, вероятно, не имеют большого смысла, поэтому давайте пройдемся по различиям между императивным и декларативным программированием, пройдя по аналогии.
Представьте, что мы не создаем программное обеспечение, а вместо этого печем пирожки для жизни. Возможно, мы плохие пекари и не знаем, как испечь вкусный пирог так, как должны.
Итак, наш босс дает нам список направлений, которые мы знаем как рецепт.
Рецепт расскажет нам, как сделать пирог. Один рецепт написан в императивном стиле примерно так:
- Смешайте 1 стакан муки
- Добавить 1 яйцо
- Добавьте 1 стакан сахара
- Вылейте смесь в кастрюлю
- Поставить сковороду в духовку на 30 минут и 350 градусов по Фаренгейту.
Декларативный рецепт будет делать следующее:
1 стакан муки, 1 яйцо, 1 стакан сахара - начальное состояние
правила
- Если все смешано, поместите в кастрюлю.
- Если все перемешано, поместите в миску.
- Если все в сковороде, поставить в духовку.
Поэтому императивные подходы характеризуются пошаговыми подходами. Вы начинаете с шага 1 и переходите к шагу 2 и так далее.
В конечном итоге вы получите какой-то конечный продукт. Таким образом, делая этот пирог, мы берем эти ингредиенты, смешиваем их, помещаем в кастрюлю и в духовку, и вы получаете конечный продукт.
В декларативном мире все по-другому. В декларативном рецепте мы должны разделить наш рецепт на две отдельные части, начнем с одной части, которая перечисляет начальное состояние рецепта, как переменные. Итак, наши переменные здесь - это количество наших ингредиентов и их тип.
Мы берем начальное состояние или исходные ингредиенты и применяем к ним некоторые правила.
Поэтому мы берем исходное состояние и пропускаем их через эти правила снова и снова, пока не получим готовый к употреблению клубничный пирог из ревеня или что-то еще.
Таким образом, в декларативном подходе мы должны знать, как правильно структурировать эти правила.
Таким образом, правила, которые мы могли бы хотеть изучить наши ингредиенты или состояния, если смешаны, положить их в кастрюлю.
С нашим начальным состоянием это не соответствует, потому что мы еще не смешали наши компоненты.
Итак, правило 2 гласит: если они не смешаны, смешайте их в миске. Хорошо, да, это правило применяется.
Теперь у нас есть миска смешанных ингредиентов в нашем штате.
Теперь мы снова применяем это новое состояние к нашим правилам.
Итак, правило 1 гласит: если ингредиенты смешаны, поместите их в кастрюлю, хорошо, да, теперь правило 1 действительно применяется, давайте сделаем это.
Теперь у нас есть это новое состояние, где ингредиенты смешиваются и в кастрюле. Правило 1 больше не актуально, правило 2 не применяется.
Правило 3 гласит: если ингредиенты находятся в сковороде, поместите их в духовку, прекрасно, что это правило относится к этому новому состоянию, давайте сделаем это.
И мы получаем вкусный горячий яблочный пирог или что-то еще.
Теперь, если вы похожи на меня, вы можете подумать, почему мы до сих пор не занимаемся императивным программированием. Это имеет смысл.
Что ж, для простых потоков да, но большинство веб-приложений имеют более сложные потоки, которые нельзя должным образом отразить при проектировании императивного программирования.
В декларативном подходе у нас могут быть некоторые начальные ингредиенты или начальное состояние, например textInput=""
, одна переменная.
Возможно, ввод текста начинается с пустой строки.
Мы берем это начальное состояние и применяем его к набору правил, определенных в вашем приложении.
-
Если пользователь вводит текст, обновите ввод текста. Ну, прямо сейчас это не относится.
-
Если шаблон отображается, рассчитайте виджет.
- Если textInput обновлен, перерисовать шаблон.
Что ж, ничего из этого не применимо, поэтому программа просто будет ждать события.
Поэтому в какой-то момент пользователь обновляет ввод текста, и тогда мы можем применить правило № 1.
Мы можем обновить это до "abcd"
Таким образом, мы только что обновили наши обновления text и textInput, правило № 2 не применяется, правило № 3 говорит, что если ввод текста является обновлением, которое только что произошло, затем повторно отображаем шаблон, а затем мы возвращаемся к правилу 2, которое говорит, что шаблон отображен, рассчитать виджет, ладно, давайте посчитаем виджет.
В целом, как программисты, мы хотим стремиться к более декларативным проектам программирования.
Императив кажется более ясным и очевидным, но декларативный подход очень хорошо масштабируется для больших приложений.
Ответ 7
Я думаю, что можно выразить функциональное программирование в обязательном порядке:
- Использование множества проверок состояния объектов и операторов
if... else
/switch
- Некоторый тайм-аут/механизм ожидания, чтобы позаботиться об асинхронности
С таким подходом возникают огромные проблемы:
- Правила/процедуры повторяются
- Statefulness оставляет шансы на побочные эффекты/ошибки
Функциональное программирование, рассматривающее функции/методы как объекты и охватывающее безгражданство, было рождено для решения тех проблем, в которые я верю.
Пример использования: приложения внешнего интерфейса, такие как логика Android, iOS или веб-приложений, вкл. связь с бэкэндом.
Другие проблемы при моделировании функционального программирования с помощью императивного/процедурного кода:
- Состояние гонки
- Сложная комбинация и последовательность событий. Например, пользователь пытается отправить деньги в банковском приложении. Шаг 1) Выполняйте все следующие действия параллельно, только продолжайте, если все хорошо a) Проверьте, все ли у вас дела хорошо (мошенничество, AML) b) Проверьте, достаточно ли у пользователя баланса c) Проверьте, действительно ли получатель действителен и хорош (мошенничество, AML) и т.д. Шаг 2) выполнить операцию переноса. Шаг 3) Показать обновление баланса пользователя и/или какое-либо отслеживание. С RxJava, например, код является кратким и разумным. Без этого я могу представить, что было бы много кода, грязного и подверженного ошибкам кода
Ответ 8
Я знаю, что этот вопрос старше, и другие уже хорошо его объяснили. Я хотел бы привести пример проблемы, которая объясняет то же самое в простых терминах.
Проблема: написание 1 таблицы.
Решение: -
По императивному стилю: =>
1*1=1
1*2=2
1*3=3
.
.
.
1*n=n
По функциональному стилю: =>
1
2
3
.
.
.
n
Пояснения в императивном стиле мы пишем инструкции более явно и которые можно назвать более упрощенными.
Где, как в функциональном стиле, вещи, которые говорят сами за себя, будут игнорироваться.