В программировании часто используется термин «парадигма программирования» — это совокупность идей и понятий, определяющих стиль написания компьютерных программ. Другими словами, это подход к программированию. Это способ концептуализации, определяющий организацию вычислений и структурирование работы, выполняемой компьютером.
Парадигма — это больше, чем просто другой алгоритм решения задачи. Как правило, при использовании разных парадигм структура кода значительно отличается. Это требует знаний, выходящих за рамки только синтаксиса языка. Например, автоматное программирование требует хотя бы базового понимания теории автоматов. Причем подавляющее большинство современных языков программирования считаются мультипарадигменными — они позволяют писать код в множестве стилей. Иногда эти стили взаимоисключающие, иногда они дополняют друг друга.
К текущему моменту мы писали код, используя две парадигмы — императивную и декларативную:
Императивная парадигма
Это стиль написания кода в виде набора последовательных инструкций или команд с активным использованием переменных. Возможно, это определение звучит страшно, но на практике императивный стиль считается доминирующим. Не считая этого курса, весь остальной код мы писали именно в императивном стиле:
<?php
// Поиск максимального числа
$numbers = [10, 20, 52, 105, 56, 89, 96];
$max = $numbers[0];
foreach ($numbers as $number) {
if ($number > $max) {
$max = $number;
}
}
print_r($max); // => 105
В императивном стиле широко используется присваивание, переменные и циклы. Эта парадигма популярна, потому что она в точности соответствует тому, как работает компьютер: последовательно выполняет инструкции и использует память для хранения промежуточных результатов. Обычно говорят, что императивная программа отвечает на вопрос «Как достичь нужного результата?».
PHP, Java, Ruby, Python, C#, Perl, JavaScript и Go относятся к императивным языкам. В таких языках доминирует императивная парадигма, сам язык толкает к ее использованию. Тем не менее это не мешает использовать и другие парадигмы в рамках этих языков.
Декларативная парадигма
Императивному стилю противопоставляют декларативный, который нередко называют функциональным. При таком стиле программа выглядит как описание нужного результата, а не как набор инструкций. Другими словами, она отвечает на вопрос «Что мы хотим получить?». Например, математическое определение факториала похоже на декларативный код:
<?php
function factorial($number)
{
if ($number <= 1) {
return 1;
} else {
return $number * factorial($number - 1);
}
}
Пример с поиском максимального числа:
<?php
$numbers = [10, 20, 52, 105, 56, 89, 96];
$max = array_reduce(
$numbers,
fn($acc, $number) => $number > $acc ? $number : $acc,
$numbers[0]
);
print_r($max); // => 105
Главное отличие декларативной парадигмы от императивной на практике — это отсутствие присваивания. Вы можете возразить, что в коде выше переменные есть, и чисто технически это правда. Присмотритесь к коду внимательнее и вы заметите, что переменная создана ровно один раз — больше она не меняется. По сути, она рассматривается как константа или логическое высказывание. В математике это звучало бы так: «Допустим, что A — это множество чисел». Что бы мы дальше ни делали, A остается всегда тем же, чем было во время определения.
Дело в том, что в математике доказательства строятся с помощью логических цепочек. Из одних утверждений следуют другие, и таким образом мы можем прийти к решению задачи. Все это возможно, только когда утверждения не изменяются. Иначе следствия могут оказаться неверными уже после того, как они были получены — значит, мы не сможем рассуждать логически.
То же самое касается и $acc
с $number
. Эти параметры всегда определяются ровно один раз, потому что каждый вызов функции при таком определении без использования ссылок не зависит от другого вызова — спасибо чистым функциям. В мире функциональных языков такую операцию называют связывание. Визуально оно выглядит как присваивание, но это не оно. Попытка связать уже связанный идентификатор (в функциональных языках нет переменных) завершится ошибкой. Ниже пример на языке Erlang:
1> A = 4.
4
2> A = 'hey'.
** exception error: no match of right hand side value hey
Отсутствие присваивания автоматически означает, что в функциональной парадигме невозможно использование циклов. Вместо них используется рекурсия. Другая важная особенность функционального стиля — это активное использование функций как объектов первого рода, обычно в функциях высшего порядка. Причем они способны заменить рекурсию в подавляющем большинстве задач, в чем мы уже убедились в предыдущих уроках. Любая задача из представленных решалась основной тройкой функций высшего порядка.
Существует довольно много языков, использующих декларативную парадигму. Обычно они не так популярны, как императивные, но прочно занимают определенные ниши и активно используются в промышленном программировании.К таким языкам относятся Haskell, Erlang, Elixir, OCaml и F#. В этих языках нет присваивания и циклов. Императивный код на них написать просто невозможно.
Немного особняком стоят Scala, Clojure и другие языки из семейства LISP. В этих языках основная парадигма — декларативная, и язык толкает к тому, чтобы писать в таком стиле. Но при необходимости на них можно написать самый настоящий императивный код с присваиванием и циклами. А вот почти все императивные языки позволяют писать декларативно. Причем одни языки имеют довольно слабую поддержку декларативной парадигмы, а другие — настолько мощную, что в них можно писать только декларативно, если хочется. К последним относится и современный JavaScript.
В PHP поддержка функционального программирования слабее, чем в большинстве других языков, но все же она достаточно серьезная. С каждой новой версией PHP вбирает в себя все больше и больше возможностей из функциональных языков, многие из которых достаточно быстро становятся популярными и начинают использоваться повсеместно — например, лямбда-функции. С другой стороны, в PHP невозможно обновить массив, не используя присваивания (в иммутабельном или неизменяемом стиле). Поэтому любой код на PHP, использующий функциональные возможности, так или иначе имеет императивные куски.
Другие парадигмы
Большинство других парадигм — это разновидности функциональной или императивной парадигм. Из самых значимых можно выделить следующие:
- Логическое программирование
- Автоматное программирование
- Объектно-ориентированное программирование
- Метапрограммирование
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Вебинар «Как самостоятельно учиться»
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.