Как стать автором
Обновить

Классификация парадигм программирования

Уровень сложностиПростой
Время на прочтение6 мин
Количество просмотров2.9K

Здравствуйте, меня зовут Дмитрий Карловский и я.. придерживаюсь следующей парадигмы мышления: всякое определение должно иметь чёткую границу между тем, что ему соответствует, и тем, что не соответствует.

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

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


Аспекты классификации

Классифицировать парадигмы можно по разным аспектам..

🎯 Целеполагание
💫 Вычисление состояний
🙌 Согласование состояний
📜 Управление потоком исполнения
🔀 Диспетчеризация
🚻 Контроль типов
🎭 Обобщение алгоритмов
🎫 Cинхронизация задач

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

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


🎯 Целеполагание

Целеполагание

Языки

Вики

⛳ Декларативное

Prolog, HTML, многие DSL и тд.

Декларативное программирование

🎢 Императивное

Почти все языки общего назначения именно такие.

Императивное программирование

⛳ Декларативное целеполагание

Описание результата, которого исполнитель может достигать разными способами.

X(a,b,c): a*X^2 + b*X + c = 0

🎢 Императивное целеполагание

Конкретные инструкции исполнителю по достижению результата.

X(a,b,c) := ( -b ± sqrt( b^2 - 4*a*c ) )/( 2*a )

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

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

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


💫 Парадигмы вычисления состояний

Вычисление

Языки

Вики

⏩ Функциональное

F#, Haskell, D и тд.

Функциональное программирование

🔄 Процедурное

C/++, Python, D и тд.

Процедурное программирование

⏩ Функциональное вычисление

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

one := 1 // one = 1
next( prev ) := prev + one
two := next( one ) // two = 2

🔄 Процедурное вычисление

Состояние может меняться со временем в процессе работы кода.

state := 1 // state = 1
state := state + 1 // state = 2

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

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


🙌 Парадигмы согласования состояний

Согласование

Языки

Вики

🏓 Интерактивное

Все не реактивные

Интерактивность в системах программирования

🚀 Реактивное

Elm, Verilog и тд.

Реактивное программирование

🏓 Интерактивное согласование

Непосредственное взаимодействие со всеми связанными состояниями.

// инициализация состояний
name := "Jin"
limit := 4
short := name.length < limit

// внесение одних изменений
name := "Jan"
short := name.length < limit

// внесение других изменений
limit := 3
short := name.length < limit

🚀 Реактивное согласование

Автоматическое поддержание заданных инвариантов (правил, не меняющихся в процессе работы программы).

// инициализация состояний
name := "Jin"
limit := 4 

// настройка инвариантов
short <= name.length < limit

// применение изменений
name := "Jan" // short = true
limit := 3 // short = false

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


🔀 Парадигмы диспетчеризации

Диспетчеризация

Языки

Вики

💎 Прямая

C, WASM и др.

🔱 Объектная

Является основой всех ООП языков: C#, Java, JS и тд.

Объектно-ориентированное программирование

🔮 Множественная

CLOS, С++, D и тд.

Мультиметод

💎 Прямая диспетчеризация

Конкретные реализации жёстко задаются в коде вызова.

sum_int( 1, 2 )
sum_float( 1.1, 2.2 )
sum_float( 1.1, float_from_int( 2 ) )

🔱 Объектная диспетчеризация

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

( 1 ).add_int( 2 ) // int:add_int
( 1.1 ).add_int( 2 ) // float:add_int
( 1.1 ).add_float( 2.2 ) // float:add_float

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

🔮 Множественная диспетчеризация

Наиболее специфичная реализация выбирается на основе типов аргументов.

sum( 1, 2 ) // sum_int_int
sum( 1.1, 2 ) // sum_float_int
sum( 1, 2.2 ) // sum_int_float
sum( 1.1, 2.2 ) // sum_float_float

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

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


🎭 Парадигмы обобщения алгоритмов

Обобщение

Языки

Вики

📦 Коробочное

Java, JS и тд.

Boxing

🎎 Шаблонное

C++, D

Template metaprogramming

Плюс на Вики есть отдельная статья про обобщённое программирование.

📦 Коробочное обобщение

Разные типы заворачиваются в обобщённую коробку, а единожды сформированный код работает уже с любыми типами через обобщённый интерфейс этой коробки.

dump( obj ) := log( obj.toString() )
dump( new Object( 1 ) )
dump( new Object( 1.1 ) )

🎎 Шаблонное обобщение

Код повторяется компилятором множество раз с подстановкой разных типов.

dump( Type )( val ) := log( Type.stringify( val ) )

dump( int )( 1 )
dump( float )( 1.1 )

🚻 Парадигмы контроля типов

Типизация

Языки

Вики

⚓ Статическая

C/++, D и тд.

Статическая типизация

🎡 Динамическая

JS, Python и тд.

Динамическая типизация

🧤 Ручная

Assembler, Forth и тд.

Бестиповые языки

⚓ Статическая типизация

Типы декларируются в коде и проверяются до его исполнения.

name : string := 1 // ошибка статического анализа: 1 - не строка

🎡 Динамическая типизация

Типы определяются и проверяются лишь в процессе исполнения кода.

count := 1
cout.sendEmail() // рантайм исключение: неизвестный метод

🧤 Ручная типизация

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

sendEmailTo( new Date ) // падение с непредсказуемым результатом

📜 Парадигмы управления потоком исполнения

Поток исполнения

Языки

Вики

🌌 Свободный

Assembler и другие низкоуровневые.

🗼 Структурный

Большинство современных языков высокого уровня.

Структурное программирование

🌌 Свободный поток исполнения

Произвольный переход к любому участку кода.

goto short_log if name = ""
short := name.length < limit
short_log:
log short // переменная может быть не задана

🗼 Структурированный поток исполнения

Жёсткие правила перехода между блоками кода: куда, как и на каких условиях возможен переход.

short_log:
	if( name = "" ) break short_log
	short := name.length < limit
	log short // переменна точно задана

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


🎫 Парадигмы синхронизации сопрограмм

Cинхронизация

Языки

Вики

📞 Явная

C#, JS и тд.

Async/await

🎠 Неявная

Go, D и тд.

Fiber

📞 Явная синхронизация

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

pipe( input, output ) // исполняется асинхронно
data := await input.read() // явно дожидаемся завершения

🎠 Неявная синхронизация

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

go pipe( iput, output ) // явно запускаем асинхронно
data := input.read() // приостанавливаемся до завершения

Продолжение следует..

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

core__dump — Видео
hyoo — Поддержка
h_y_o_o — Обсуждения
mam_mol — Новости

А на этом пока что всё. С вами был.. классный пара-Димитрий Карловский.


Актуальный оригинал на $hyoo_page.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какую парадигму вы применяете?
73.33% ⛳ Декларативное целеполагание11
86.67% 🎢 Императивное целеполагание13
33.33% ⏩ Функциональное вычисление5
73.33% 🔄 Процедурное вычисление11
66.67% 🏓 Интерактивное согласование10
33.33% 🚀 Реактивное согласование5
0% 🌌 Свободный поток исполнения0
86.67% 🗼 Структурированный поток исполнения13
20% 💎 Ручная диспетчеризация3
73.33% 🔱 Объектная диспетчеризация11
46.67% 🔮 Множественная диспетчеризация7
53.33% 📦 Коробочное обобщение8
26.67% 🎎 Шаблонное обобщение4
53.33% 📞 Явная синхронизация8
26.67% 🎠 Неявная синхронизация4
Проголосовали 15 пользователей. Воздержались 5 пользователей.
Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
+18
Комментарии47

Публикации

Ближайшие события