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

StackOverflow https://stackoverflow.com/questions/129628

Вопрос

Я постоянно слышу, как этот термин используется в разных контекстах.Что это такое?

Это было полезно?

Решение

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

Примерами декларативных языков программирования являются SQL и Пролог.

Другие советы

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

Независимость от контекста

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

Брать yacc В качестве примера.Это генератор синтаксического анализатора.компилятор — внешний декларативный DSL для описания грамматики языка, позволяющий автоматически генерировать анализатор для этого языка на основе описания.Благодаря независимости от контекста с помощью такой грамматики можно делать много разных вещей:

  • Создайте синтаксический анализатор C для этой грамматики (исходный вариант использования для yacc)
  • Создайте синтаксический анализатор C++ для этой грамматики.
  • Создайте парсер Java для этой грамматики (используя Jay)
  • Создайте синтаксический анализатор C# для этой грамматики (используя GPPG).
  • Создайте парсер Ruby для этой грамматики (используя Racc).
  • Создайте древовидную визуализацию для этой грамматики (используя GraphViz).
  • просто выполните красивую печать, необычное форматирование и подсветку синтаксиса самого исходного файла yacc и включите его в свое справочное руководство в качестве синтаксической спецификации вашего языка.

И многое другое…

Оптимизация

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

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

Свободно:

Декларативное программирование имеет тенденцию к:

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

Императивное программирование имеет тенденцию к:

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

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

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

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

Определение

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

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

Пример таблицы

В двух ответах упоминалось программирование электронных таблиц.В тех случаях, когда программирование электронных таблиц (т.н.формулы) не имеет доступа к изменяемым Глобальный состояние, то это декларативное программирование.Это связано с тем, что изменяемые значения ячеек являются монолитными. вход и выход принадлежащий main() (вся программа).Новые значения не записываются в ячейки после выполнения каждой формулы, поэтому они не изменяются в течение всего срока службы декларативной программы (выполнения всех формул в электронной таблице).Таким образом, по отношению друг к другу формулы рассматривают эти изменяемые ячейки как неизменяемые.Функция RT имеет доступ неизменный глобальное состояние (а также изменчивый местный состояние).

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

Вот пример.

В CSS (используемом для стилизации HTML-страниц), если вы хотите, чтобы элемент изображения имел высоту 100 пикселей и ширину 100 пикселей, вы просто «объявляете», что это то, что вы хотите, следующим образом:

#myImageId {
height: 100px;
width: 100px;
}

Вы можете считать CSS декларативным языком «таблиц стилей».

Механизм браузера, который читает и интерпретирует этот CSS позволяет сделать изображение таким высоким и таким широким, как ему хочется.Различные браузерные движки (например, движок для IE, движок для Chrome) реализуют эту задачу по-разному.

Их уникальные реализации, конечно же, написаны НЕ на декларативном языке, а на процедурном языке, например, на ассемблере, C, C++, Java, JavaScript или Python.Этот код представляет собой набор шагов, которые необходимо выполнить шаг за шагом (и может включать вызовы функций).Он может выполнять такие действия, как интерполяция значений пикселей и рендеринг на экране.

Декларативное программирование — это картинка, а императивное программирование — это инструкции по рисованию этой картины.

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

Когда вы используете XML для разметки данных, вы используете декларативное программирование, потому что вы говорите: «Это человек, у него день рождения, а там — почтовый адрес».

Несколько примеров того, как декларативное и императивное программирование объединяются для большего эффекта:

  • Windows Presentation Foundation использует декларативный синтаксис XML для описания того, как выглядит пользовательский интерфейс и каковы отношения (привязки) между элементами управления и базовыми структурами данных.

  • Структурированные файлы конфигурации используют декларативный синтаксис (простой, например пары «ключ=значение»), чтобы определить, что означает строка или значение данных.

  • HTML размечает текст тегами, описывающими роль каждого фрагмента текста по отношению ко всему документу.

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

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

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

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

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

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

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

Декларативный против.Императив

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

Определение декларативности как что делать и императивен, как как сделать.Неоднозначный случай:что" это "как» в программе, которая выводит программу — компилятор.

Очевидно, неограниченная рекурсия, которая делает язык Тьюринга полным, аналогично и в семантике — не только в синтаксической структуре оценки (т.н.операционная семантика).Логически это пример, аналогичный теореме Гёделя:любая полная система аксиом также противоречива».Задумайтесь над противоречивой странностью этой цитаты!Это также пример, демонстрирующий, что выражение семантики не имеет доказуемой границы, поэтому мы не можем доказать2 что программа (и, аналогично, ее семантика) останавливается, т.е.теорема остановки.

Теоремы о неполноте вытекают из фундаментальной природы нашей Вселенной, которая, как сказано во Втором законе термодинамики, такова:энтропия (он жеколичество независимых возможностей) стремится к максимуму навсегда».Кодирование и проектирование программы никогда не завершаются — она жива! — потому что она пытается удовлетворить потребности реального мира, а семантика реального мира постоянно меняется и имеет тенденцию к увеличению возможностей.Люди никогда не перестают открывать что-то новое (в том числе ошибки в программах ;-).

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

Определение:


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

Императивное свойство3 является двойственным, где семантика противоречива по составу и/или может быть выражена с помощью вариаций наборов утверждений.


Это определение декларативности характерно местный в семантической области действия, что означает, что требуется, чтобы модульная семантика сохраняла свое последовательное значение независимо от того, где и как она создается и используется в Глобальный объем.Таким образом, каждая декларативная модульная семантика должна быть внутренне ортогональной всем возможным другим, а не невозможным (из-за теорем о неполноте). Глобальный алгоритм или модель для подтверждения согласованности, что также является целью «Больше - не всегда лучше» Роберта Харпера, профессора компьютерных наук Университета Карнеги-Меллон, одного из разработчиков Standard ML.

Примеры этой модульной декларативной семантики включают функторы теории категорий, например. тот Applicative, номинальная типизация, пространства имен, именованные поля и w.r.t.на операционный уровень семантики, а затем чистое функциональное программирование.

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

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

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


Редактировать:я разместил следующий комментарий в блог Роберта Харпера:

в функциональном программировании...диапазон изменения переменной – это тип

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

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

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

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

Как и я написал В 2012 году, который, по -видимому, аналогичный консенсус комментариев в твой недавний блог, Это декларативное программирование является попыткой захватить представление о том, что предполагаемая семантика никогда не бывает непрозрачной.Примерами непрозрачной семантики является зависимость от порядка, зависимость от стирания семантики более высокого уровня на уровне оперативной семантики (например, Актеры не являются конверсиями, а урегулированные дженерики ограничивают семантику более высокого уровня) и зависимость от значений переменных, которые не могут быть проверены (доказано правильно) языком программирования.

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

Таким образом, одним однозначным и четким атрибутом декларативного языка может быть то, что его вывод может быть доказан, чтобы подчиняться некоторому перечисляемому набору генеративных правил.Например, для какой -либо конкретной программы HTML (игнорируя различия в том, как переводчики расходятся), которая не сценария (т.е.не является заполнением), тогда его выходная изменчивость может быть перечислена.Или более кратко программа HTML является чистой функцией ее изменчивости.Ditto программа электронной таблицы является чистой функцией ее входных переменных.

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

Леси Лэмпорт написал Сказка о том, как Евклид могла бы работать вокруг теорем неполноты Гёделя, применяемых к математическим доказательствам в контексте языка программирования с помощью конгруэнтности между типами и логикой (переписка карри-ховарда и т. Д.).

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

Другими словами, вы не пишете алгоритмы, состоящие из выражений, вы просто компонуете все так, как хотите.Два хороших примера — HTML и WPF.

Эта статья в Википедии представляет собой хороший обзор: http://en.wikipedia.org/wiki/Declarative_programming

Описывать компьютеру то, что вы хотите, а не то, как что-то сделать.

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

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

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

В самом наивном и крайнем смысле (который я утверждал в своем предыдущем ответе), декларативное программирование (DP) избегает всех сохраненных изменяемых состояний, поэтому упорядочивание и/или дублирование программных инструкций может НЕТ изменить поведение (семантику) программы.

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

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

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

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

  • коммутативный (можно переупорядочить)
  • ассоциативный (может быть перегруппирован)
  • идемпотентный (может повторяться без изменения смысла)
  • монотонный (объявления не вычитают информацию)

Важным моментом является то, что все это структурные свойства и ортогональны предмету.Декларативная речь не о «Что против.Как".Мы можем объявить (представить и ограничить) "как" так же легко, как мы объявляем "что". Декларативная речь идет о структуре, а не о содержании. Декларативное программирование оказывает существенное влияние на то, как мы абстрагируем и реорганизуем наш код, а также на то, как мы разбиваем его на подпрограммы, но не так сильно на модель предметной области.

Часто мы можем перейти от императивного к декларативному, добавив контекст.Например.из «Поверните налево.(...подождите...) Поверните направо." на "Боб повернет налево на пересечении улиц Фу и Бар в 11:01.Боб повернет направо на пересечении улиц Бар и Баз в 11:06». Обратите внимание, что в последнем случае предложения идемпотентны и коммутативны, тогда как в первом случае перестановка или повторение предложений сильно изменило бы смысл программы.

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

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

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

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

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

Это может показаться странным, но я бы добавил Excel (или любую другую электронную таблицу) в список декларативных систем.Хороший пример этому приведен здесь.

Я бы объяснил это тем, что ДП — это способ выразить

  • А выражение цели, условия - то, что ищем.Есть один, может быть, или много?
  • Некоторые известные факты
  • Правила, расширяющие известные факты

...и там, где есть вычитающий двигатель, обычно работающий с объединение алгоритм поиска целей.

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

Оно все чаще означает очень мало, поскольку оно имеет определение, данное пользователями выше.Должно быть ясно, что существует пропасть между декларативным программированием Haskell и декларативным программированием HTML.

Еще пара примеров декларативного программирования:

  • Разметка ASP.Net для привязки данных.Например, он просто говорит «заполните эту сетку этим источником» и оставляет на усмотрение системы, как это произойдет.
  • Выражения Linq

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

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

foreach (object item in MyList)
{
   DoSomething(item);
}

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

MyList.ForEach(DoSometing);

Это, конечно, более кратко.Но я уверен, что у вас есть нечто большее, чем просто сохранение двух строк кода здесь и там.Производительность, например.По-старому обработка должна была выполняться последовательно.Что, если бы у метода .ForEach() была возможность сигнализировать о том, что он может автоматически обрабатывать параллельную обработку?Теперь вы внезапно сделали свой код многопоточным очень безопасным способом и изменили только одну строку кода.И на самом деле, есть расширение для .Net, который позволяет вам сделать именно это.

  • Если вы перейдете по этой ссылке, вы попадете на сообщение в блоге моего друга.Весь пост немного длинный, но вы можете прокрутить вниз до заголовка «Проблема» _и забрать его там без проблем.*

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

Опять же, это зависит от того, в чем проблема в целом.Возможно, вам придется сократить его из-за программы.Надеюсь, это поможет, и вам понадобится обратная связь, если это не так.Спасибо.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top