it-swarm.com.ru

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

Большинство основных языков, включая языки объектно-ориентированного программирования (ООП), такие как C #, Visual Basic, C++ и Java, были разработаны, чтобы в первую очередь поддерживать императивное (процедурное) программирование, тогда как языки, подобные Haskell/gofer, являются чисто функциональными. Кто-нибудь может уточнить, в чем разница между этими двумя способами программирования? 

Я знаю, что выбор способа программирования зависит от требований пользователя, но почему рекомендуется изучать функциональные языки программирования?

114
Swapnil Kotwal

Определение: Императивный язык использует последовательность утверждений, чтобы определить, как достичь определенной цели. Говорят, что эти операторы изменяют состояние программы, поскольку каждое из них выполняется по очереди.

Примеры: Java - императивный язык. Например, можно создать программу для добавления серии чисел:

 int total = 0;
 int number1 = 5;
 int number2 = 10;
 int number3 = 15;
 total = number1 + number2 + number3; 

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

Функциональные языки: Парадигма функционального программирования была явно создана для поддержки чисто функционального подхода к решению проблем. Функциональное программирование является формой декларативного программирования.

Преимущества чистых функций: Основная причина реализации функциональных преобразований как чистых функций состоит в том, что чистые функции являются составными: то есть автономными и не сохраняющими состояния. Эти характеристики дают ряд преимуществ, в том числе следующие: Повышенная читаемость и удобство обслуживания. Это связано с тем, что каждая функция предназначена для выполнения конкретной задачи с учетом своих аргументов. Функция не зависит от какого-либо внешнего состояния.

Более легкое повторное развитие. Поскольку код легче реорганизовать, изменения в дизайне часто проще реализовать. Например, предположим, что вы пишете сложное преобразование, а затем понимаете, что некоторый код повторяется несколько раз в преобразовании. Если вы выполняете рефакторинг с помощью чистого метода, вы можете вызывать свой чистый метод по своему усмотрению, не беспокоясь о побочных эффектах. 

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

Для OOP людей или Императивные языки:

Объектно-ориентированные языки хороши, когда у вас есть фиксированный набор операций над вещами, и когда ваш код развивается, вы в первую очередь добавляете новые вещи. Это может быть достигнуто путем добавления новых классов, которые реализуют существующие методы, а существующие классы остаются одни.

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

Минусы:

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

Когда эволюция идет не так, у вас есть проблемы:

  • Добавление новой операции в объектно-ориентированную программу может потребовать редактирования многих определений классов для добавления нового метода 
  • Добавление нового вида вещей в функциональную программу может потребовать редактирования многих определений функций для добавления нового случая.
121
user2102654

Вот разница:

Императив:

  • Начните
  • Включите обувь размером 9 1/2.
  • Освободите место в своем кармане, чтобы хранить массив [7] ключей.
  • Положите ключи в комнате для ключей в кармане.
  • Войдите в гараж.
  • Открытый гараж.
  • Введите автомобиль.

... и так далее и тому подобное ...

  • Положите молоко в холодильник.
  • Стоп.

Декларативный, из которых функционал является подкатегорией:

  • Молоко - это полезный напиток, если у вас нет проблем с перевариванием лактозы.
  • Обычно молоко хранится в холодильнике.
  • Холодильник - это коробка, в которой вещи хранятся в прохладе.
  • Магазин - это место, где продаются товары.
  • Под «продажей» мы подразумеваем обмен вещей на деньги.
  • Также обмен денег на вещи называется «покупка».

... и так далее, и так далее ...

  • Убедитесь, что у нас есть молоко в холодильнике (когда оно нам нужно - для ленивых функциональных языков).

Резюме: на императивных языках вы говорите компьютеру, как изменять биты, байты и слова в его памяти и в каком порядке. В функциональных мы сообщаем компьютеру, что такое вещи, действия и т.д. Например, мы говорим, что факториал 0 равен 1, а факториал любого другого натурального числа является произведением этого числа и факториала его предшественника. Мы не говорим: чтобы вычислить факториал для n, зарезервировать область памяти и сохранить там 1, затем умножить число в этой области памяти на числа от 2 до n и сохранить результат в том же месте и в конце, область памяти будет содержать факториал.

192
Ingo

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

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

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

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

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

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

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

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

7
Jakub Keller

Большинство современных языков в той или иной степени являются как императивными, так и функциональными, но для лучшего понимания функционального программирования лучше всего взять пример чисто функционального языка, такого как Haskell, в отличие от императивного кода на не очень функциональном языке, таком как Java/c #. Я считаю, что это всегда легко объяснить на примере, поэтому ниже один. 

Функциональное программирование: вычислить факториал n, т.е. n! то есть n x (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's execution  

factorial 0 = 1
factorial n = n * factorial (n - 1)
factorial 3

-- | for brevity let's 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/c # lang, а первую часть - как ограничение самого языка в отличие от Haskell для перегрузки функции на значение (ноль) и, следовательно, можно сказать, что это не пуристический функциональный язык, с другой Со стороны можно сказать, что он поддерживает функциональную прогу. в некоторой степени.

Раскрытие информации: ни один из вышеприведенных кодов не протестирован/не выполнен, но, надеюсь, должен быть достаточно хорош, чтобы передать концепцию; Также я был бы признателен за комментарии для любой такой коррекции :) 

7
old-monk

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

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

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

На этой основе программ как выражений, состоящих из функций и значений, строится целая практическая парадигма языков, концепций, «функциональных паттернов», комбинаторов и систем различных типов и алгоритмов оценки.

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

4
Romil pawar

Императивный стиль программирования практиковался в веб-разработке с 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, которое говорит, что шаблон отображен , рассчитать виджет, ладно, давайте посчитаем виджет.

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

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

1
Daniel

Я думаю, что функциональное программирование можно выразить императивно:
- Использование множества проверок состояния объектов и операторов if... else/switch
- Некоторый механизм тайм-аут/ожидания, чтобы позаботиться об асинхронности 

С таким подходом возникают огромные проблемы:
- Правила/процедуры повторяются - Statefulness оставляет шансы на побочные эффекты/ошибки

Функциональное программирование, рассматривающее функции/методы как объекты и охватывающее безгражданство, рождается для решения этих проблем. 

Пример использования: приложения внешнего интерфейса, такие как логика Android, iOS или веб-приложений, вкл. связь с бэкэндом

0
ericn