Я продолжаю слышать этот термин в нескольких разных контекстах. Что это?
Я продолжаю слышать этот термин в нескольких разных контекстах. Что это?
Ответы:
Декларативное программирование - это когда вы пишете свой код таким образом, что он описывает то, что вы хотите сделать, а не то, как вы хотите это сделать. Это зависит от компилятора, чтобы выяснить, как.
Примерами декларативных языков программирования являются SQL и Prolog.
Другие ответы уже проделали фантастическую работу, объясняя, что такое декларативное программирование, поэтому я просто приведу несколько примеров того, почему это может быть полезно.
Декларативные программы не зависят от контекста . Поскольку они объявляют только то, что является конечной целью, но не промежуточные шаги для достижения этой цели, одну и ту же программу можно использовать в разных контекстах. Это трудно сделать с императивными программами , потому что они часто зависят от контекста (например, скрытого состояния).
Взять хотя yacc
бы пример. Это генератор парсеров ака. compiler compiler, внешний декларативный DSL для описания грамматики языка, так что анализатор для этого языка может автоматически генерироваться из описания. Из-за его независимости от контекста вы можете делать много разных вещей с такой грамматикой:
yacc
)И многое другое ...
Поскольку вы не прописываете компьютеру, какие шаги и в каком порядке предпринять, он может гораздо более свободно переставлять вашу программу, возможно, даже выполнять некоторые задачи параллельно. Хорошим примером является планировщик запросов и оптимизатор запросов для базы данных SQL. Большинство баз данных SQL позволяют отображать запрос, который они фактически выполняют, по сравнению с запросом, который вы просили их выполнить. Часто эти запросы ничего не выглядяткак друг друга Планировщик запросов принимает во внимание то, о чем вы даже не мечтали: например, задержку вращения диска, или тот факт, что какое-то совершенно другое приложение для совершенно другого пользователя только что выполнило аналогичный запрос и таблицу, которой вы являетесь. соединение с тем, что вы так усердно работали, чтобы избежать загрузки, уже есть в памяти.
Существует интересный Компромисс здесь: машина должна работать , чтобы выяснить , как сделать что - то , чем это было бы в императивном языке, но когда это делает фигуру его, он имеет гораздо больше свободы и гораздо больше информации для оптимизации этап.
Неплотно:
Декларативное программирование имеет тенденцию к:
Императивное программирование имеет тенденцию к: -
В результате императивный стиль помогает читателю понять механику того, что система на самом деле делает, но может дать мало понимания проблемы, которую она призвана решить. С другой стороны, декларативный стиль помогает читателю понять предметную область и подход, который система использует для решения проблемы, но менее информативен в механике.
Реальные программы (даже написанные на языках, которые поддерживают концы спектра, такие как ProLog или C) имеют тенденцию к тому, чтобы оба стиля присутствовали в различной степени в разных точках, чтобы удовлетворить различные сложности и коммуникационные потребности произведения. Один стиль не превосходит другой; они просто служат различным целям, и, как и во многих вещах в жизни, умеренность является ключевым фактором.
Вот пример.
В CSS (используется для стилизации HTML-страниц), если вы хотите, чтобы элемент изображения имел высоту 100 пикселей и ширину 100 пикселей, вы просто «объявляете», что вы хотите следующее:
#myImageId {
height: 100px;
width: 100px;
}
Вы можете считать CSS декларативным языком «таблиц стилей».
Движок браузера, который читает и интерпретирует этот CSS, свободен, чтобы изображение выглядело таким высоким и таким широким, как ему хочется. Различные движки браузера (например, движок для IE, движок для Chrome) будут выполнять эту задачу по-разному.
Их уникальные реализации, конечно, НЕ написаны на декларативном языке, а на процедурном, таком как Assembly, C, C ++, Java, JavaScript или Python. Этот код представляет собой набор шагов, которые необходимо выполнить шаг за шагом (и может включать вызовы функций). Это может делать такие вещи, как интерполяция значений пикселей и рендеринг на экране.
Извините, но я должен не согласиться со многими другими ответами. Я хотел бы остановить это запутанное недопонимание определения декларативного программирования.
Определение
Ссылочная прозрачность (RT) подвыражений является единственным обязательным атрибутом декларативного выражения программирования , поскольку это единственный атрибут, который не используется в императивном программировании.
Другие процитированные атрибуты декларативного программирования происходят из этого RT. Пожалуйста, нажмите гиперссылку выше для подробного объяснения.
Пример электронной таблицы
В двух ответах упоминается программирование электронных таблиц. В случаях, когда программирование электронных таблиц (или формул) не имеет доступа к изменяющемуся глобальному состоянию, тогда это декларативное программирование. Это потому , что изменяемые значения ячеек являются монолитным вводом и выводом из main()
(всей программы). Новые значения не записываются в ячейки после выполнения каждой формулы, поэтому они не изменяются в течение всего срока действия декларативной программы (выполнение всех формул в электронной таблице). Таким образом, по отношению друг к другу формулы рассматривают эти изменчивые клетки как неизменные. RT-функции разрешен доступ к неизменяемому глобальному состоянию (а также к изменяемому локальному состоянию ).
Таким образом, способность изменять значения в ячейках при завершении программы (как вывод из main()
) не делает их изменяемыми хранимыми значениями в контексте правил. Ключевым отличием является то, что значения ячеек не обновляются после выполнения каждой формулы электронной таблицы, поэтому порядок выполнения формул не имеет значения. Значения ячеек обновляются после выполнения всех декларативных формул.
Декларативное программирование - это картинка, где императивное программирование - это инструкции для рисования этой картины.
Вы пишете в декларативном стиле, если вы «рассказываете, что это такое», а не описываете шаги, которые компьютер должен предпринять, чтобы добраться туда, куда вы хотите.
Когда вы используете XML для разметки данных, вы используете декларативное программирование, потому что вы говорите: «Это человек, у которого день рождения, и у него есть уличный адрес».
Некоторые примеры, где декларативное и императивное программирование объединяются для большего эффекта:
Windows Presentation Foundation использует декларативный синтаксис XML для описания того, как выглядит пользовательский интерфейс и каковы связи (привязки) между элементами управления и базовыми структурами данных.
Структурированные файлы конфигурации используют декларативный синтаксис (так же просто, как пары «ключ = значение»), чтобы определить, что означает строка или значение данных.
HTML отмечает текст тегами, которые описывают роль каждого фрагмента текста по отношению ко всему документу.
Декларативное программирование - это программирование с декларациями, то есть декларативными предложениями. Декларативные предложения имеют ряд свойств, которые отличают их от императивных предложений. В частности, декларации:
Важным моментом является то, что все это структурные свойства и они ортогональны предмету. Декларативный не о «Что против как» . Мы можем объявить (представить и ограничить) «как» так же легко, как и «что» . Декларативный - это структура, а не содержание.Декларативное программирование оказывает существенное влияние на то, как мы абстрагируем и рефакторизируем наш код, и на то, как мы его модульно превращаем в подпрограммы, но не так сильно на модель предметной области.
Часто мы можем перейти от императивного к декларативному, добавив контекст. Например, из "Поверните налево. (... подождите ...) Поверните направо". to «Боб повернет налево на пересечении Фу и Бара в 11:01. Боб повернет направо на пересечении Бара и Бэза в 11:06». Обратите внимание, что в последнем случае предложения являются идемпотентными и коммутативными, тогда как в первом случае перестановка или повторение предложений сильно изменили бы смысл программы.
Что касается монотонности , объявления могут добавлять ограничения, которые вычитают возможности . Но ограничения по-прежнему добавляют информацию (точнее, ограничения - это информация). Если нам нужны изменяющиеся во времени объявления, типично моделировать это с явной временной семантикой - например, от «шар плоский» к «шар плоский в момент времени T». Если у нас есть две противоречивые декларации, у нас есть несовместимая декларативная система, хотя это может быть решено путем введения мягких ограничений (приоритетов, вероятностей и т. Д.) Или использования паранепротиворечивой логики.
представьте себе страницу Excel. С колонками, заполненными формулами для расчета налоговой декларации.
Вся логика объявлена в ячейках, порядок вычисления определяется самой формулой, а не процедурно.
Это своего рода декларативное программирование. Вы объявляете проблемное пространство и решение, а не поток программы.
Пролог - единственный декларативный язык, который я использую. Это требует другого типа мышления, но хорошо учиться, если просто подвергнуть вас чему-то другому, кроме типичного процедурного языка программирования.
Я усовершенствовал свое понимание декларативного программирования с декабря 2011 года, когда дал ответ на этот вопрос. Здесь следует мое текущее понимание.
Длинная версия моего понимания (исследования) подробно описана по этой ссылке , которую вы должны прочитать, чтобы получить глубокое понимание резюме, которое я приведу ниже.
В императивном программировании изменяемое состояние хранится и читается, поэтому упорядочение и / или дублирование инструкций программы может изменить поведение (семантику) программы (и даже вызвать ошибку, то есть непреднамеренное поведение).
В самом наивном и крайнем смысле (который я утверждал в моем предыдущем ответе) декларативное программирование (DP) избегает всех сохраняемых изменяемых состояний, поэтому упорядочение и / или дублирование программных инструкций НЕ МОЖЕТ изменить поведение (семантику) программы. ,
Однако такое экстремальное определение не будет очень полезным в реальном мире, так как почти каждая программа использует хранимое изменяемое состояние. В примере таблицы соответствует этому определению крайнего ДП, потому что весь программный код выполняется до завершения одной статической копии входного состояния, до того , как новые состояния сохраняются. Затем, если какое-либо состояние изменяется, это повторяется. Но большинство реальных программ не могут быть ограничены такой монолитной моделью изменений состояния.
Более полезное определение DP заключается в том, что упорядочение и / или дублирование инструкций программирования не изменяет никакой непрозрачной семантики. Другими словами, не происходит скрытых случайных изменений в семантике - любые изменения в порядке команд программы и / или дублировании вызывают только предполагаемые и прозрачные изменения в поведении программы.
Следующим шагом было бы поговорить о том, какие модели программирования или парадигмы помогают в DP, но это не вопрос здесь.
Functional programming
это модное слово в наши дни, которое по сути является подмножеством декларативного программирования. LINQ в языке C # является элементом функционального программирования, когда сам язык является обязательным по своей природе. Таким образом, C # становится своего рода гибридом в соответствии с этим определением.
Это метод программирования, основанный на описании того, что что- то должно делать или быть, а не на том, как это должно работать.
Другими словами, вы не пишете алгоритмы, составленные из выражений, вы просто размечаете, как вы хотите, чтобы все было. Два хороших примера - это HTML и WPF.
Эта статья в Википедии - хороший обзор: http://en.wikipedia.org/wiki/Declarative_programming
Поскольку я написал свой предыдущий ответ, я сформулировал новое определение декларативного свойства, которое приводится ниже. Я также определил императивное программирование как двойственное свойство.
Это определение лучше того, которое я дал в моем предыдущем ответе, потому что оно лаконично и носит более общий характер. Но это может быть более трудным для понимания, потому что значение теорем о неполноте, применимых к программированию и жизни в целом, людям трудно обернуть вокруг себя.
В приведенном объяснении этого определения обсуждается роль, которую чисто функциональное программирование играет в декларативном программировании.
Декларативный и императивный
Декларативное свойство является странным, тупым, и его трудно уловить в технически точном определении, которое остается общим и не двусмысленным, потому что это наивное представление о том, что мы можем объявить значение (то есть семантику) программы, не вызывая непреднамеренных побочных эффектов. Между выражением смысла и избеганием непреднамеренных эффектов существует внутреннее противоречие, которое на самом деле вытекает из теорем о неполноте программирования и нашей вселенной.
Упрощенно, технически неточно и часто неоднозначно определять декларативное как « что делать » и обязательно как « как делать » . Неоднозначный случай - это « что » - это « как » в программе, которая выводит программу - компилятор.
Очевидно, что неограниченная рекурсия, делающая язык Тьюринга полным , также аналогично семантике, а не только синтаксической структуре оценки (операционная семантика). Это логически пример, аналогичный теореме Гёделя: « любая полная система аксиом также несовместна ». Обдумайте противоречивую странность этой цитаты! Это также пример, который демонстрирует, что выражение семантики не имеет доказуемой границы, поэтому мы не можем доказать 2, что программа (и аналогично ее семантике) останавливается, как теорема Остановки.
Теоремы о неполноте проистекают из фундаментальной природы нашей вселенной, которая, как указано во Втором законе термодинамики, гласит: « Энтропия (или число независимых возможностей) стремится к максимуму навсегда ». Кодирование и дизайн программы никогда не заканчиваются - она жива! - потому что она пытается удовлетворить потребности реального мира, а семантика реального мира всегда меняется и имеет тенденцию к увеличению возможностей. Люди никогда не перестают открывать новые вещи (в том числе ошибки в программах ;-).
Чтобы точно и технически охватить это вышеупомянутое желаемое понятие в этой странной вселенной, которая не имеет границ (учтите, что «вне» нашей вселенной нет), требуется краткое, но обманчиво-непростое определение, которое будет звучать неправильно, пока оно не будет объяснено. глубоко.
Определение:
В декларативном свойстве может существовать только один возможный набор операторов, которые могут выражать каждую конкретную модульную семантику.
Императивное свойство 3 является двойственным, где семантика несовместима по составу и / или может быть выражена с помощью вариаций наборов утверждений.
Это определение декларативного является исключительно локальным в семантической области, что означает, что оно требует, чтобы модульная семантика поддерживала свое непротиворечивое значение независимо от того, где и как она была реализована и использована в глобальной области. Таким образом, каждая декларативная модульная семантика должна быть по сути ортогональной ко всем возможным другим, а не невозможным (из-за теорем о неполноте) глобальным алгоритмом или моделью, свидетельствующей о последовательности, что также является точкой « Больше не всегда лучше » Роберта Харпера, профессора Информатика в Университете Карнеги-Меллона, один из разработчиков Standard ML.
Примеры этих модульных декларативной семантики включают категории теории функторы , например , в
Applicative
, номинальный ввод, пространств имен, названных полей и WRT на операционном уровне семантики то чисто функционального программирования.Таким образом, хорошо разработанные декларативные языки могут более четко выражать значение , хотя и с некоторой потерей общности в том, что может быть выражено, и в то же время выигрывают в том, что может быть выражено с внутренней последовательностью.
Примером вышеупомянутого определения является набор формул в ячейках программы для работы с электронными таблицами, которые, как ожидается, не будут иметь одинакового значения при перемещении в разные ячейки столбцов и строк, то есть изменились идентификаторы ячеек. Идентификаторы ячеек являются частью и не являются лишними по отношению к предполагаемому значению. Таким образом, каждый результат электронной таблицы уникален по отношению к идентификаторам ячеек в наборе формул. Последовательная модульная семантика в этом случае заключается в использовании идентификаторов ячеек в качестве ввода и вывода чистых функций для формул ячеек (см. Ниже).
Язык гипертекстовой разметки, то есть HTML - язык статических веб-страниц - является примером высоко (но не совсем 3 ) декларативного языка, который (по крайней мере, до HTML 5) не обладал способностью выражать динамическое поведение. HTML, пожалуй, самый простой язык для изучения. Для динамического поведения императивный язык сценариев, такой как JavaScript, обычно сочетался с HTML. HTML без JavaScript соответствует декларативному определению, поскольку каждый номинальный тип (т. Е. Теги) сохраняет свое непротиворечивое значение в рамках композиции в правилах синтаксиса.
Конкурентное определение для декларативного - это коммутативные и идемпотентные свойства семантических операторов, то есть, что операторы могут быть переупорядочены и продублированы без изменения значения. Например, операторы, присваивающие значения именованным полям, могут быть переупорядочены и продублированы без изменения смысла программы, если эти имена являются модульными по отношению к любому подразумеваемому порядку. Имена иногда подразумевают порядок, например, идентификаторы ячеек включают их столбец и положение строки - перемещение итога в электронной таблице меняет его значение. В противном случае эти свойства неявно требуют глобальногосогласованность семантики. Как правило, невозможно разработать семантику операторов, чтобы они оставались непротиворечивыми при случайном порядке или дублировании, поскольку порядок и дублирование являются неотъемлемой частью семантики. Например, выражения «Foo существует» (или конструкция) и «Foo не существует» (и уничтожение). Если кто-то считает случайное несоответствие эндемичным для предполагаемой семантики, то он принимает это определение как достаточно общее для декларативного свойства. По сути, это определение является бесполезным как обобщенное определение, потому что оно пытается сделать последовательность ортогональной семантике, то есть бросить вызов факту, что вселенная семантики динамически не ограничена и не может быть охвачена в глобальной парадигме когерентности.
Требование коммутативных и идемпотентных свойств для (структурной оценки порядка) операционной семантики нижнего уровня преобразует операционную семантику в декларативную локализованную модульную семантику, например, чисто функциональное программирование (включая рекурсию вместо императивных циклов). Тогда порядок выполнения деталей реализации не влияет (то есть распространяется глобально ) на согласованность семантики более высокого уровня. Например, порядок оценки (и теоретически также дублирования) формул электронной таблицы не имеет значения, потому что выходные данные не копируются на входные данные до тех пор, пока не будут вычислены все выходные данные, т.е. аналогично чистым функциям.
C, Java, C ++, C #, PHP и JavaScript не являются особенно декларативными. Синтаксис Copute и синтаксис Python более декларативно связаны с намеченными результатами , то есть согласованной синтаксической семантикой, которая устраняет посторонние, так что можно легко понять код после того, как он его забыл. Copute и Haskell усиливают детерминизм операционной семантики и поощряют « не повторяться » (DRY), потому что они допускают только чисто функциональную парадигму.
2 Даже там, где мы можем доказать семантику программы, например, с помощью языка Coq, это ограничивается семантикой, выраженной в типизации , и типизация никогда не может охватить всю семантику программы, даже для языков, которые не полный по Тьюрингу, например, с помощью HTML + CSS можно выразить несовместимые комбинации, которые, таким образом, имеют неопределенную семантику.
3 Многие объяснения неправильно утверждают, что только императивное программирование имеет синтаксически упорядоченные операторы. Я прояснил эту путаницу между императивным и функциональным программированием . Например, порядок операторов HTML не уменьшает согласованность их значения.
Изменить: я разместил следующий комментарий в блоге Роберта Харпера:
в функциональном программировании ... диапазон изменения переменной является типом
В зависимости от того, как можно отличить функциональное от императивного программирования, ваш «присваиваемый» в императивной программе также может иметь тип, ограничивающий его изменчивость.
Единственное неразборчивое определение, которое я в настоящее время ценю для функционального программирования, - это: а) функции в качестве объектов и типов первого класса, б) предпочтение рекурсии над циклами и / или в) чистые функции, то есть те функции, которые не влияют на желаемую семантику программы, когда она запоминается ( таким образом, совершенно чистого функционального программирования не существует в денотационной семантике общего назначения из-за воздействий операционной семантики, например, выделения памяти ).
Идемпотентное свойство чистой функции означает, что вызов функции для ее переменных может быть заменен ее значением, что обычно не относится к аргументам императивной процедуры. Чистые функции кажутся декларативными по отношению к несоставленным переходам между типами ввода и результата.
Но состав чистых функций не поддерживает такую согласованность, потому что можно моделировать императивный процесс побочного эффекта (глобального состояния) на чистом функциональном языке программирования, например, IOMonad на Haskell, и, кроме того, совершенно невозможно предотвратить это в любой тьюринговский полный чисто функциональный язык программирования.
Как я писал в 2012 году, что похоже на сходное согласие с комментариями в вашем недавнем блоге , декларативное программирование - это попытка уловить идею, что предполагаемая семантика никогда не бывает непрозрачной. Примерами непрозрачной семантики являются зависимость от порядка, зависимость от стирания семантики более высокого уровня на уровне операционной семантики (например, приведения не являются преобразованиями, а уточненные обобщенные элементы ограничивают семантику более высокого уровня ), а также зависимость от значений переменных, которые не могут быть проверены (доказано). правильно) языком программирования.
Таким образом, я пришел к выводу, что только полные языки, не являющиеся тьюринговыми, могут быть декларативными.
Таким образом, одним однозначным и отличительным признаком декларативного языка может быть то, что его вывод может быть доказан как подчиняющийся некоторому перечисляемому набору генеративных правил. Например, для любой конкретной HTML-программы (без учета различий в способах расхождения интерпретаторов), которая не является сценарием (то есть не завершена по Тьюрингу), ее выходная изменчивость может быть перечисляемой. Или, более кратко, программа HTML является чистой функцией ее изменчивости. То же самое относится к программе электронных таблиц, которая является чистой функцией ее входных переменных.
Поэтому мне кажется, что декларативные языки являются антитезой неограниченной рекурсии , т.е. согласно второй теореме Гёделя о неполноте самореференциальные теоремы не могут быть доказаны.
Лези Лэмпорт написал сказку о том, как Евклид мог обойти теоремы Гёделя о неполноте, примененные к математическим доказательствам в контексте языка программирования, для сравнения между типами и логикой (соответствие Карри-Говарда и т. Д.).
Декларативное программирование - это «акт программирования на языках, которые соответствуют ментальной модели разработчика, а не операционной модели машины».
Разница между декларативным и императивным программированием хорошо иллюстрируется проблемой анализа структурированных данных.
Императивная программа будет использовать взаимно рекурсивные функции для потребления ввода и генерации данных. Декларативная программа выражает грамматику, которая определяет структуру данных, чтобы затем их можно было проанализировать.
Разница между этими двумя подходами заключается в том, что декларативная программа создает новый язык, который более точно сопоставлен с ментальной моделью проблемы, чем с ее основным языком.
Я бы объяснил это, так как DP - это способ выразить
... и там, где есть механизм вычитания, обычно работающий с алгоритмом унификации , чтобы найти цели.
Насколько я могу судить, он начал использоваться для описания систем программирования, таких как Пролог, потому что пролог (предположительно) предназначен для объявления вещей абстрактно.
Это все больше значит очень мало, поскольку имеет определение, данное пользователями выше. Должно быть ясно, что существует декларация между декларативным программированием на Haskell, в отличие от декларативного программирования на HTML.
Пара других примеров декларативного программирования:
Декларативное программирование - это хорошо, потому что оно может помочь упростить вашу ментальную модель * кода и потому, что оно может в конечном итоге стать более масштабируемым.
Например, допустим, у вас есть функция, которая делает что-то для каждого элемента в массиве или списке. Традиционный код будет выглядеть так:
foreach (object item in MyList)
{
DoSomething(item);
}
Ничего страшного там нет. Но что, если вы используете более декларативный синтаксис и вместо этого определяете DoSomething () как действие? Тогда вы можете сказать это так:
MyList.ForEach(DoSometing);
Это, конечно, более кратко. Но я уверен, что у вас больше проблем, чем просто сохранение двух строк кода здесь и там. Производительность, например. По старинке обработка должна была выполняться последовательно. Что если у метода .ForEach () есть способ сообщить о том, что он может обрабатывать обработку параллельно, автоматически? Внезапно вы сделали свой код многопоточным очень безопасным способом и изменили только одну строку кода. И, собственно, есть расширение для .Net, которое позволяет вам это делать.
Это зависит от того, как вы отправляете ответ на текст. В целом вы можете посмотреть на программу с определенной точки зрения, но это зависит от того, под каким углом вы смотрите на проблему. Я начну с программы: Dim Bus, Car, Time, Height As Integr
Опять же, это зависит от того, что проблема в целом. Возможно, вам придется сократить его из-за программы. Надеюсь, что это помогает и нужна обратная связь, если это не так. Спасибо.