Лабораторные - Императивное и декларативное функциональное программирование


  Императивное программирование — это парадигма программирования  (стиль написания исходного кода компьютерной программы), в которой задается последовательность действий, необходимых для получения результата. В нем используются переменные, операторы присваивания и составные выражения. Это такой стиль программирования, при котором вы описываете, как добиться желаемого результата. Примерами императивных языков являются Java, Python, JavaScript, C, C++.

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

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

- в исходном коде программы записываются иструкции (команды);

- инструкции должны выполняться последовательно;

- данные, получаемые при выполнении предыдущих инструкций, могут читаться из памяти последующими инструкциями;

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

  Декларативное программирование распространено не так обширно, как императивное, хотя оказывает большое влияние. Смысл декларативного программирования в том, что программы пишут в виде некоторых ограничений и правил. Логические языки, такие, как Пролог, предлагают описывать ограничения в виде фактов и правил.

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

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

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

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

  Самым сложным является тот факт, что разница между декларативным и императивным подходами часто понятна интуитивно, но ее сложно задать определением. Лучшее объяснение — это сочетание метафор и примеров кода.

Императивный подход (как): Я вижу, что тот угловой столик свободен. Мы пойдем туда и сядем там.

Декларативный подход (что): Столик для двоих, пожалуйста.

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

Примеры кода: дан массив чисел, надо написать функцию, которая вернет массив чисел, где каждое число из исходного массива удваивается. Т.е. [1, 2, 3] -> [2, 3, 6]

Императивный стиль:
 

function double (arr) {
  let results = [];
  for (let i = 0; i < arr.length; i++){
    results.push(arr[i] * 2);
  }
  return results;
}


Декларативный стиль:
 

function double (arr) {
  return arr.map((item) => item * 2);
}