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

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

Или насколько неверным было мое представление о React

Feb 11, 2018 · 4 min read

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

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

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

Согласно этой и этой информации:

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

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

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

Хорошо, вот метафора.

Декларативное программирование — это как попросить вашего друга нарисовать пейзаж. Тебе все равно, как он рисует, это зависит от него.

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

Продемонстрируй в коде

Ладно, ладно, вот несколько примеров кода. У нас есть кнопка, которая меняет цвет при нажатии. Я начну с императивного примера:

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

Возможно, различия незначительны. У нас по-прежнему есть логика, которая говорит: если красный, значит синий, но есть одна огромная разница. Пример c React никогда не затрагивает элемент. Он просто объявляет, что элемент должен отображаться с учетом нашего текущего состояния (далее — state). Он фактически не манипулирует самим DOM.

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

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

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

Чего следует избегать

Я либо допустил, либо позволил допустить все эти ошибки в коде, над которым работал. Это всего лишь советы.

Источник

Основные принципы программирования: императивное и декларативное программирование

Рассказывает Тайлер МакГиннис, Google Developer Expert

Вы наверняка слышали о таких понятиях, как императивное и декларативное программирование, и скорее всего гуглили определения. И поэтому вы наверняка видели что-то подобное: «Императивное программирование — это описание того, как ты делаешь что-то, а декларативное — того, что ты делаешь. Это объяснение отлично подходит тем, кто уже разобрался в этом вопросе — но не новичкам.

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

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

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

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

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

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

«Я у Ашана. Как мне пройти до твоего дома?»

«Пройди через северный выход парковки и поверни налево. Сядь на автобус 678 и выйди на остановке «Улица Победы». Поверни направо, как если бы ты шёл в Икею. Иди прямо и поверни направо у первого светофора. На следующем светофоре поверни налево. Номер моего дома — 134.»

Мой адрес: Энск, улица Победы, дом 134.

Неважно, как я попаду к твоему дому, важно, на какой машине я приеду. У неё будет или императивная механическая КПП, или декларативная автоматическая КПП. Достаточно метафор?

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

Итак, я повторюсь: многие (если не все) декларативные подходы имеют слой неких императивных абстракций.

Теперь мы перейдём от приятных метафор к реальному коду. Сперва посмотрим, какие языки являются декларативными, а какие — императивными:

Вот типичные примеры на SQL и HTML:

Пока неплохо. Давайте рассмотрим примеры на JavaScript.

Представьте, что вы на собеседовании. Откройте консоль и ответьте на следующие вопросы.

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

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

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

Ну а третий? В нём я немного схитрил, использовав React — но обратите внимание, что все три императивные ошибки исправлены. React замечателен тем, что в нём вы можете создавать декларативные пользовательские интерфейсы. Смотря на компонент Btn, сразу понятно, как будет выглядеть интерфейс. Кроме того, состояния «живут» не в DOM, а в самом React-компоненте.

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

Источник

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

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

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

Источник

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

Предыстория

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

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

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

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

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

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

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

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

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

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

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

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

Пример на 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 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии