В чем разница между функциональными и императивными языками программирования?

Большинство основных языков, включая языки объектно-ориентированного программирования (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

Функциональное программирование - это форма декларативного программирования, которая описывает логику вычислений, и порядок выполнения полностью не подчеркивается.

Проблема: я хочу превратить это существо из лошади в жирафа.

  • Удлинить шею
  • Удлинить ноги
  • Применить пятна
  • Дайте существу черный язык
  • Удалить конский хвост

Каждый элемент может быть запущен в любом порядке для получения одинакового результата.

Императивное программирование носит процедурный характер. Государство и порядок важны.

Проблема: я хочу оставить свою машину.

  1. Обратите внимание на начальное состояние ворот гаража
  2. Остановить машину на дороге
  3. Если дверь гаража закрыта, откройте дверь гаража, запомните новое состояние; в противном случае продолжить
  4. Вытащить машину в гараж
  5. Закрыть гаражные ворота

Каждый шаг должен быть сделан, чтобы достичь желаемого результата. Вытягивание в гараж, когда дверь гаража закрыта, приведет к поломке двери гаража.

Ответ 5

Функциональное программирование - это "программирование с функциями", где функция имеет некоторые ожидаемые математические свойства, включая ссылочную прозрачность. Из этих свойств вытекают дополнительные свойства, в частности, знакомые этапы рассуждений, обеспечиваемые замещаемостью, которые приводят к математическим доказательствам (т.е. Оправдывают уверенность в результате).

Отсюда следует, что функциональная программа является просто выражением.

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

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

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

Ответ 6

Императивный стиль программирования практиковался в веб-разработке с 2005 года вплоть до 2013 года.

С императивным программированием мы выписали код, который перечислял, что именно должно делать наше приложение, шаг за шагом.

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

В ответах упоминается декларативное программирование, и в связи с этим я скажу, что декларативное программирование перечисляет некоторые правила, которым мы должны следовать. Затем мы предоставляем то, что мы называем некоторым начальным состоянием нашего приложения, и мы позволяем этим правилам как бы определять поведение приложения.

Теперь, эти быстрые описания, вероятно, не имеют большого смысла, поэтому давайте пройдемся по различиям между императивным и декларативным программированием, пройдя по аналогии.

Представьте, что мы не создаем программное обеспечение, а вместо этого печем пирожки для жизни. Возможно, мы плохие пекари и не знаем, как испечь вкусный пирог так, как должны.

Итак, наш босс дает нам список направлений, которые мы знаем как рецепт.

Рецепт расскажет нам, как сделать пирог. Один рецепт написан в императивном стиле примерно так:

  1. Смешайте 1 стакан муки
  2. Добавить 1 яйцо
  3. Добавьте 1 стакан сахара
  4. Вылейте смесь в кастрюлю
  5. Поставить сковороду в духовку на 30 минут и 350 градусов по Фаренгейту.

Декларативный рецепт будет делать следующее:

1 стакан муки, 1 яйцо, 1 стакан сахара - начальное состояние

правила

  1. Если все смешано, поместите в кастрюлю.
  2. Если все перемешано, поместите в миску.
  3. Если все в сковороде, поставить в духовку.

Поэтому императивные подходы характеризуются пошаговыми подходами. Вы начинаете с шага 1 и переходите к шагу 2 и так далее.

В конечном итоге вы получите какой-то конечный продукт. Таким образом, делая этот пирог, мы берем эти ингредиенты, смешиваем их, помещаем в кастрюлю и в духовку, и вы получаете конечный продукт.

В декларативном мире все по-другому. В декларативном рецепте мы должны разделить наш рецепт на две отдельные части, начнем с одной части, которая перечисляет начальное состояние рецепта, как переменные. Итак, наши переменные здесь - это количество наших ингредиентов и их тип.

Мы берем начальное состояние или исходные ингредиенты и применяем к ним некоторые правила.

Поэтому мы берем исходное состояние и пропускаем их через эти правила снова и снова, пока не получим готовый к употреблению клубничный пирог из ревеня или что-то еще.

Таким образом, в декларативном подходе мы должны знать, как правильно структурировать эти правила.

Таким образом, правила, которые мы могли бы хотеть изучить наши ингредиенты или состояния, если смешаны, положить их в кастрюлю.

С нашим начальным состоянием это не соответствует, потому что мы еще не смешали наши компоненты.

Итак, правило 2 гласит: если они не смешаны, смешайте их в миске. Хорошо, да, это правило применяется.

Теперь у нас есть миска смешанных ингредиентов в нашем штате.

Теперь мы снова применяем это новое состояние к нашим правилам.

Итак, правило 1 гласит: если ингредиенты смешаны, поместите их в кастрюлю, хорошо, да, теперь правило 1 действительно применяется, давайте сделаем это.

Теперь у нас есть это новое состояние, где ингредиенты смешиваются и в кастрюле. Правило 1 больше не актуально, правило 2 не применяется.

Правило 3 гласит: если ингредиенты находятся в сковороде, поместите их в духовку, прекрасно, что это правило относится к этому новому состоянию, давайте сделаем это.

И мы получаем вкусный горячий яблочный пирог или что-то еще.

Теперь, если вы похожи на меня, вы можете подумать, почему мы до сих пор не занимаемся императивным программированием. Это имеет смысл.

Что ж, для простых потоков да, но большинство веб-приложений имеют более сложные потоки, которые нельзя должным образом отразить при проектировании императивного программирования.

В декларативном подходе у нас могут быть некоторые начальные ингредиенты или начальное состояние, например textInput="", одна переменная.

Возможно, ввод текста начинается с пустой строки.

Мы берем это начальное состояние и применяем его к набору правил, определенных в вашем приложении.

  1. Если пользователь вводит текст, обновите ввод текста. Ну, прямо сейчас это не относится.

  2. Если шаблон отображается, рассчитайте виджет.

  3. Если 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

Пояснения в императивном стиле мы пишем инструкции более явно и которые можно назвать более упрощенными.

Где, как в функциональном стиле, вещи, которые говорят сами за себя, будут игнорироваться.