что такое декларативный подход в программировании

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

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

Если посмотреть определение в англоязычной Википедии, мы увидим приблизительно следующее:

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

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

Давайте попробуем объяснить более простыми словами:

То есть в первом случае у нас стоит вопрос «Как?», а во втором — «Что?» И все равно разница ясна лишь интуитивно, поэтому без практических примеров не обойтись. Но начать лучше стоит с метафор.

Давайте представим, что вы попросили вашего товарища нарисовать пейзаж, а как он это сделает, для вас значения не имеет — это декларативный путь, когда дается ответ на вопрос «Что именно надо сделать?»

В императивном случае ситуация следующая:

— вы попросили товарища нарисовать пейзаж;

— он попросил, к примеру, Никаса Сафронова, рассказать ему, как рисуются пейзажи;

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

Императивные и декларативные языки программирования

Примеры декларативных языков программирования:

Императивные языки:

Также выделяют смешанные языки:

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

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

Декларативный язык SQL:

Язык HTML:

И снова код

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

— написать функцию с названием double, принимающую массив чисел и возвращающую новый массив, причем каждый элемент нового массива больше исходного в 2 раза:

— написать функцию с названием add, принимающую массив и возвращающую сумму всех элементов массива:

— используя библиотеку jQuery (либо чистый язык JavaScript), выполните добавление обработчика событий click к элементу с идентификатором (id), равным btn. При нажатии выполните переключение класса highlight и замените текст на Add Highlight либо Remove Highlight с учетом того, каково текущее состояние элемента.

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

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

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

Теперь стало гораздо лучше, не находите?

Обратите внимание, что в первых 2-х примерах применяются встроенные в язык JavaScript методы: map и reduce. То есть в нашем случае декларати вное программирование — это абстракции над императивными реализациями, но на деле нас мало волнует, как эти методы реализованы. Мы тоже не меняем состояния, да и сам программный код стал более читаемым.

В 3-м примере при написании кода мы пошли на хитрость, так как задействовали библиотеку языка JavaScript под названием React. Но важно не это, а то, что все 3 императивные ошибки нами исправлены. Да и само программи рование на React хорошо еще и тем, что предоставляет возможность создавать декларативные пользовательские интерфейсы. Если посмотреть на тот же компонент Btn, сразу становится понятно, как конкретно станет выглядеть интерфейс. А еще состояния «живут» не в DOM, а непосредственно в React-компоненте.

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

Источник

Декларативный подход к программированию

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

Что такое декларативное программирование:

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

Противоположностью этому принципу является императивное программирование, описывающее отдельные операции с помощью алгоритмов. Проще говоря, императивные программы содержат алгоритмы, которые достигают желаемой цели, в то время как декларативные языки задают цель, а алгоритмизация предоставляется программе (интерпретатору) языка.

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

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

Подходы к декларативному программированию:

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

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

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

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

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

Вывод:

В этой статье вы прочитали что такое декларативный подход к программированию и всё остальное с этим связанное.

Источник

Мышление в стиле Ramda: Декларативное программирование

Данный пост является четвёртой частью серии о функциональном програмировании под названием «Мышление в стиле Ramda».

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

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

Но сначала, небольшое введение.

Императивность vs Декларативность

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

Другое подобное разделение заключается в императивном програмировании против декларативного.

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

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

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

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

Декларативные заменители

Поскольку мы программируем на JavaScript, императивном языке, это нормально — использовать стандартные императивные конструкции при написании «нормального» JavaScript кода.

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

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

Арифметика

Во второй части мы реализовали серию арифметических трансформаций для демонстрации конвеера:

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

Мы можем использовать add(1) и subtract(1) для увеличения и уменьшения, но так как эти две операции такие распространённые, Ramda предоставляет inc и dec вместо них.

Так что мы можем ещё немного упростить наш конвеер:

Сравнение

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

Обратите внимание, что некоторые из наших функций использут стандартные операторы сравнения ( === и >= в данном случае). Как вы можете предположить сейчас, Ramda также предоставляет заменители для всего этого.

Обратите внимание, что эти функции, как кажется, принимают свои аргументы в нормальном порядке (первый аргумент больше второго?). Это имеет смысл, когда мы используем их в изоляции, но может сбивать с толку при объединении функций. Эти функции нарушают принцип «данные идут последними», так что нам нужно быть осторожными, когда мы используем их в наших конвеерах и подобных им ситуациях. И именно здесь flip и заполнитель (__) могут принести пользу.

В дополнение к equals есть ещё identical для определения, являются ли два значения ссылками на то же пространство в памяти.

Логика

В основном, || используется для получения значений по умолчанию. К примеру, мы можем написать что-нибудь вроде этого:

Это распространённая идиома, и чаще всего работающая, но полагающаяся на JavaScript логику определения «ложности». Что если 0 является валидным параметром? Так как 0 является ложным значением, мы получим значение линии равное 80.

Условия

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

ifElse

Как мы упомянули выше, функции сравнения не работают подобно функциям объединения, так что здесь нам нужно начать использовать заполнитель ( __ ). Мы также можем применить lte вместо этого:

В данном случае, мы должны читать это как «21 меньше или равно age ». Я собираюсь придерживаться версии с заменителем в оставшейся части поста, так как я нахожу это более читабельным и менее запутывающим.

Константы

Функции-константы весьма полезны в ситуациях, подобных этой. Как вы можете предположить, Ramda предоставляет нам сокращение. В данном случае, сокращение называется always.

Ramda также предоставляет T и F в качестве дальнейших сокращений для always(true) и always(false)

Тождественность

Вторая ветвь сравнения ( a => a ) — это другой типичный паттерн в функциональном программировании. Это известно как «тождественность» (не знаю точного перевода термина «identity function», просто выберу этот — прим. пер.). То есть, это функция, которая просто возвращает тот аргумент, который она получила.

Как вы уже можете ожидать, Ramda предоставляет нам функцию identity:

«when» и «unless»

Если, как в нашем случае, вторая ветвь является тождественностью, мы можем использовать when вместо ifElse :

Мне не понадобилось использовать cond в моём коде с Ramda, но я писал подобный код на Lisp много лет назад, так что cond чувствуется старым другом.

Заключение

Мы рассмотрели набор функций, которые Ramda предоставляет нам для превращения нашего императивного кода в декларативный функциональный код.

Далее

Это распространённый паттерн, и вновь Ramda предоставляем нам инструменты для того чтобы привести всё это к более чистому виду. Следующий пост, «Бесточечная нотация» рассматривает способы, позволяющие упростить функции, следующие подобному паттерну.

Источник

Чем отличается императивное программирование от декларативного

Предыстория

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

Большинство было вполне обычными, типа «сколько лет вы пользуетесь фреймворком Х?», но один мне показался интересным (я даже туда откликнулась, но #меняневзяли).

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

В чем же отличия?

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

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

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

Это что ни на есть декларативный стиль, но при этом с примесью императивного.

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

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

И получатель такого сообщения уже сам разбирается, какие шаги для этого надо предпринять.

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

Пример на JS

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

Наверное, правильно называть один стиль «более декларативным», а другой — «более императивным».

Источник

Можно ли использовать декларативный и императивный стили написания программ одновременно?

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

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

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

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

Данная статья — размышление о совместимости декларативной и императивной парадигм программирования и возможности их одновременного использования в рамках одного языка программирования одновременно.

Что такое «Декларативное программирование»?

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

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

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

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

И заставил задуматься один абзац в конце статьи следующего содержания:

«Чисто декларативные» компьютерные языки зачастую неполны по Тьюрингу — так как теоретически не всегда возможно порождение исполняемого кода по декларативному описанию. Это иногда приводит к спорам о корректности термина «декларативное программирование» (менее спорным является «декларативное описание решения» или, что то же самое, «декларативное описание задачи»).

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

Например в языке Prolog, который обычно и приводят в качестве примера декларативного языка программирования, «замаскированным» императивным оператором является знак вопроса. Он кажется естественным и логичным, как же без него? Но по своей сути, это императивная конструкция!

Тоже самое касается и языка SQL. Он тоже как бы декларативный, но неожиданно все его команды являются императивными по сути. SELECT, CREATE, ALTER, DROP, INSERT, UPDATE, DELETE и т. д., а декларативными являются только описания условий их выполнения!

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

А что отличает декларативные языки программирования от императивных?

Согласно определению, декларативными языками программирования их называют из-за возможности записать некие условия в декларативном стиле. Но кроме этого, в декларативных языках как правило присутствует и некий внутренний механизм поиска решений. Подобный «вычислитель» есть и в SQL и Prolog и во многих других декларативных языках.

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

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

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

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

Получилась вот такая функционально — эквивалентная программа на С++, которая максимально приближена по стилю к декларативному прототипу:

Конечно, текст на С++ получается значительно многословней, чем вариант на Прологе, но по сути, это почти дословное повторение декларативного стиля написания кода. Тем более, не стоит забывать про рассуждения в начале статьи об изначальном выборе концепции при создании языка и «принуждении» программистов пользоваться только одной, изначально выбранной парадигмой разработки.

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

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

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

Что мешает совместить императивный и декларативный стили написания в рамках одной программы?

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

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

А декларативный стиль написания программ стал появляться только после создания высокоуровневых языков программирования. И основная цель создания данных языков сместилась на поиск решения конечного пользователя, а не на упрощение генерации бинарных файлов с машинными инструкциями. Если внимательно посмотреть на приведенные выше примеры кода, то можно заметить, что в них определения данных и операторы для их обработки идут вперемешку, (для примера на С++ это определение лямбд функции), что кардинально отличается от императивного подхода.

Так может быть, основная особенность декларативного стиля как раз и заключается в том, что в нем не разделяются «данные» и «действия над данными»? Или как вариант, можно не указывать выполняемые действия над данными вовсе (как в некоторых SQL конструкциях)?

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

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

Проверка гипотезы в новом языке программирования

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

Правда с учетом изначальных ограничений синтаксиса нового языка (запрет на применение операторов в виде зарезервированных ключевых слов), в качестве оператора проверки условия была выбрана синтаксическая конструкция, соответствующая по смыслу термину «следует», т.е. тире и угловая скобка «->».

В результате, условный оператор получился практически математический, который легко объединяется в последовательности для реализации проверки множественных условий вида «else if». А для объединения сразу нескольких логического операторов между собой и для отделения их от последующего действия, операторы проверки условия можно заключать в круглые скобки.

В общем случае условный оператор в новом языке программирования имеет вид:

Или расширенный вариант, для наглядности записанный с отступами:

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

счетный цикл для работы с итератором*:
*) Разъяснение операторов «итератор» приводится в этой статье

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

Примерно это и требовалось показать!

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

Ну и пять копеечек про ООП. Как ни странно:

1) В нем таки есть декларативная часть, все эти pubic, private, virtual, etc
2) Эта декларативная часть, внезапно, элегантно позволяет реализовывать декомпозицию и управление сложностью.
3) При наличии перегрузок, можно поиграть в алгебраическое мышление, рассматривая взаимодействие двух объектов как бинарную операцию.

Ух ты, ООП — это обкатанная практикой технология, которая совмещает декларатив с императивом и вроде позволяет освоившим ее вкусно кушать и мягко спать!

Источник

Понравилась статья? Поделиться с друзьями:

Не пропустите наши новые статьи:

  • Что такое декларативное программирование
  • Что такое дек в программировании
  • Что такое деинсталляция программы
  • Что такое деинсталляция программного
  • Что такое деинсталляция программного обеспечения

  • Операционные системы и программное обеспечение
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest
    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии