Разное

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

Содержание

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

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


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

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

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

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

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

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

Больше метафор!

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

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


Императивный ответ:

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

Декларативный ответ:

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

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

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

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

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

  • Императивные: C, C++, Java.
  • Декларативные: SQL, HTML.
  • Смешанные (могут быть таковыми): JavaScript, C#, Python.

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

SELECT * FROM Users WHERE Country=’Mexico’;
<article>
  <header>
    <h2>Declarative Programming</h2>
    <p>Sprinkle Declarative in your verbiage to sound smart</p>
  </header>
</article>

Достаточно взглянуть на них, чтобы понять, что происходит. Они декларативны, заявляя, что должно быть сделано, а не как. Вы описываете желаемый результат, не углубляясь в инструкции. Неважно, как будут выбраны пользователи из Мексики. Неважно, как браузер распарсит ваш article. Важно, что вы получите мексиканских пользователей и новый header и paragraph на сайте.

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

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

  1. Напишите функцию, называющуюся double, которая принимает массив чисел и возвращает новый массив, каждый элемент которого в два раза больше входного: double([1,2,3]) -> [2,4,6].
  2. Напишите функцию, называющуюся add, которая принимает массив и возвращает сумму всех его элементов: add([1,2,3]) -> 6.
  3. Используя jQuery (или чистый JavaScript), добавьте обработчик события click к элементу с id, равным btn. По нажатию переключите класс highlight и смените текст на Add Highlight или Remove Highlight, в зависимости от текущего состояния элемента.

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

function double (arr) {
  let results = []
  for (let i = 0; i < arr.length; i++){
    results.push(arr[i] * 2)
  }
  return results
}
function add (arr) {
  let result = 0
  for (let i = 0; i < arr.length; i++){
    result += arr[i]
  }
  return result
}
$("#btn").click(function() {
  $(this).toggleClass("highlight")
  $(this).text() === 'Add Highlight'
    ? $(this).text('Remove Highlight')
    : $(this).text('Add Highlight')
})

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

  1. Очевидно, что все они описывают, как решить проблему: мы явно указываем все шаги.
  2. Это уже не так очевидно для тех, кто не привык думать декларативно, или даже функционально. В каждом примере происходит изменение какого-либо состояния. В первых двух примерах происходило изменение переменной results, а в третьей состояние было в самой DOM – и его мы тоже изменяли.
  3. Это уже субъективно, но я считаю, что код выше нечитаем. Я не могу с первого взгляда понять, что происходит — вместо этого мне приходится читать код построчно.

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

function double (arr) {
  return arr.map((item) => item * 2)
}
function add (arr) {
  return arr.reduce((prev, current) => prev + current, 0)
}
<Btn
  onToggleHighlight={this. handleToggleHighlight}
  highlight={this.state.highlight}>
    {this.state.buttonText}
</Btn>

Гораздо лучше ?

Заметьте, что в первых двух примерах я использовал встроенные методы JavaScript, map и reduce. Как видите, декларативные решения вновь оказались абстракциями над императивными реализациями. Но нас не интересует, как реализованы эти методы. Мы также не изменяем состояния, да и читается этот код лучше.

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

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

Адаптированный перевод статьи «Imperative vs Declarative Programming»

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

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

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

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

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

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

Обоснование и основы императивного программирования

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

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

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

Многие императивные языки программирования (такие как Fortran , BASIC и C ) являются абстракциями языка ассемблера .

История императивных и объектно-ориентированных языков

Самыми ранними императивными языками были машинные языки исходных компьютеров. На этих языках инструкции были очень простыми, что облегчало аппаратную реализацию, но затрудняло создание сложных программ. FORTRAN , разработанный Джоном Бэкусом в International Business Machines (IBM) с 1954 года, был первым крупным языком программирования, устраняющим препятствия, создаваемые машинным кодом при создании сложных программ. FORTRAN был скомпилированным языком, который позволял именованные переменные, сложные выражения, подпрограммы и многие другие функции, которые теперь распространены в императивных языках. В следующие два десятилетия были разработаны многие другие важные языки императивного программирования высокого уровня. В конце 1950-х и 1960-х годах был разработан АЛГОЛ, чтобы упростить выражение математических алгоритмов, и он даже служил языком перевода операционной системы для некоторых компьютеров. MUMPS (1966) довел императивную парадигму до логической крайности, не имея вообще никаких операторов, полагаясь исключительно на команды, даже до такой степени, что команды IF и ELSE были независимыми друг от друга, связанными только внутренней переменной с именем $ ТЕСТ. COBOL (1960) и BASIC (1964) были попытками сделать синтаксис программирования более похожим на английский. В 1970-х годах Паскаль был разработан Никлаусом Виртом , а C был создан Деннисом Ричи, когда он работал в Bell Laboratories . Вирт разработал Модула-2 и Оберон . Для нужд Соединенных Штатов Министерства обороны , Ишбиа и команда Honeywell начали проектирование Ada в 1978 году, после того, как проект в 4 года , чтобы определить требования к языку. Спецификация была впервые опубликована в 1983 году с изменениями в 1995, 2005 и 2012 годах.

В 1980-х годах наблюдался стремительный рост интереса к объектно-ориентированному программированию . Эти языки были обязательными по стилю, но добавляли функции для поддержки объектов . В последние два десятилетия ХХ века появилось много таких языков. Smalltalk -80, первоначально задуманный Аланом Каем в 1969 году, был выпущен в 1980 году Исследовательским центром Xerox в Пало-Альто ( PARC ). Исходя из концепций в другой объектно-ориентированный Язык- Симула (который считается первым в мире объектно-ориентированный язык программирования , разработанный в 1960 — е годы) — Бьерн Страуструп разработан C ++ , объектно-ориентированный язык , основанный на C . Разработка C ++ началась в 1979 году, а первая реализация была завершена в 1983 году. В конце 1980-х и 1990-х наиболее заметными императивными языками, основанными на объектно-ориентированных концепциях, были Perl , выпущенный Ларри Уоллом в 1987 году; Wolfram Language , выпущенный Wolfram Research в 1988 году; Python , выпущенный Гвидо ван Россумом в 1990 году; Visual Basic и Visual C ++ (включая Microsoft Foundation Class Library (MFC) 2.0), выпущенные Microsoft в 1991 и 1993 годах соответственно; PHP , выпущенный Расмусом Лердорфом в 1994 году; Java , выпущенная Sun Microsystems в 1995 году, JavaScript , Бренданом Эйчем ( Netscape ) и Ruby , Юкихиро «Матц» Мацумото, выпущенные в 1995 году. Microsoft .NET Framework (2002) является обязательной по своей сути, как и ее основные целевые языки, VB.NET и C #, которые работают на нем; однако функциональный язык Microsoft F # также работает на нем.

Смотрите также

Примечания

Рекомендации

  • Пратт, Терренс В. и Марвин В. Зельковиц. Языки программирования: проектирование и реализация , 3-е изд. Энглвуд Клиффс, Нью-Джерси: Prentice Hall, 1996.
  • Себеста, Роберт В. Концепции языков программирования , 3-е изд. Ридинг, Массачусетс: издательство Addison-Wesley Publishing Company, 1996.
Первоначально основано на статье Стэна Зайберта «Императивное программирование» из Nupedia , под лицензией GNU Free Documentation License .

Декларативное и императивное программирование в имитационном моделировании сложных многокомпонентных систем Текст научной статьи по специальности «Компьютерные и информационные науки»

МОДЕЛИРОВАНИЕ СОЦИАЛЬНО-_^^^КОНОМИЧЕСКИХПРОЦЕССО^_

УДК 519. 87

Ю. И. Бродский, А. Н. Мягков

ДЕКЛАРАТИВНОЕ И ИМПЕРАТИВНОЕ ПРОГРАММИРОВАНИЕ В ИМИТАЦИОННОМ МОДЕЛИРОВАНИИ СЛОЖНЫХ МНОГОКОМПОНЕНТНЫХ СИСТЕМ

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

Е-mail: [email protected]

Ключевые слова: имитационное моделирование, сложные системы, парадигмы программирования, поведение системы, объектно-ориентированное программирование, декларативное программирование.

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

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

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

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

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

Задача синтеза многокомпонентной системы. Эта задача, по крайней мере на первый взгляд, хорошо укладывается в императивную парадигму программирования. В самом деле, отталкиваясь от имеющихся знаний об отдельных компонентах сложной системы, мы беремся построить синтез всей системы, основанный на воспроизведении известного поведения каждой ее компоненты, и при этом собираемся наблюдать и изучать поведение системы в целом, не известное нам заранее. В основе синтеза многокомпонентной системы лежит идея, высказанная в работах Н.П. Бусленко, — дать каждой из компонент, про которые нам все известно, максимально проявить себя, учитывая при этом и все межкомпонентные связи [2].

Основным инструментом реализации проектов императивного программирования являются объектноориентированные языки программирования. В свое время эти языки возникли в значительной мере как ответ на запросы исследователей, занимавшихся имитационным моделированием. Одним из самых первых объектноориентированных языков можно считать язык Симула-67. Структура сложной системы, состоящей из большого числа экземпляров различных типов компонент, хорошо описывается иерархией классов объектноориентиро-ванного программирования (ООП). У ООП множество известных всем достоинств, которые и сделали этот подход бесспорным лидером в программировании последних 25 лет. Однако применительно к поставленной задаче ООП имеет существенные недостатки.

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

собой, наблюдать характеристики и других объектов и пользоваться их методами, однако все это делается в некотором смысле «вручную». По сути, поведение коллектива программистов, приступающих к созданию сложного проекта и вооруженных набором библиотек полезных классов, можно уподобить человеку, имеющему несколько компьютеров, каждый из которых оснащен большим набором полезных прикладных программ, но из системных программ — только загрузчик, и поставили перед ним задачу сделать из этого распределенную систему. Понятно, что современный программист возмутился бы страшно: «Так не бывает! Где моя сетевая операционная система? Где, наконец, ПО промежуточного уровня?» Однако при создании сложной системы средствами ООП дело обстоит именно так: к сложности содержательных вычислений предметной области добавляется еще и сложность организации поведения объектов, а также их связей и взаимодействий между собой.

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

В истории развития информатики известно несколько подходов к объектному программированию, в силу которых они обладают поведением. Эти подходы зародились в среде исследователей, занимавшихся проблемами искусственного интеллекта, и известны как ак-торная модель [3] и агентное программирование [4, 5]. Несмотря на то что авторы настоящей работы согласны с главным посылом этих подходов — важностью моделирования поведения агентов системы — детали описания этого поведения [3—5], по их мнению, слишком окрашены спецификой проблематики искусственного интеллекта, т. е. недостаточно универсальны. Так, у Шохема [4, 5] поведение — это поведение ментальное, о состоянии которого рассуждают в категориях «убеждения», «обязанности», «способности» и т. д. Ак-торная модель Хьюитта [3] интересна своей ориентированностью на параллельные вычисления, однако асинхронный обмен акторов сигналами-сообщениями и порождение новых акторов представляются нам избыточными конструкциями, затрудняющими реализацию подобных систем [6].

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

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

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

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

Одной из первых сред программирования, воплотивших рассмотренную выше концепцию разделения описания сложной системы на декларативную и императивную составляющие, была разработанная в ВЦ АН СССР инструментальная система имитационного моделирования MISS (Multilingual Instrumental Simulation System). Концеп-

ция программирования, лежащая в ее основе, предложена в работах [7, 8], а полное описание среды моделирования на уровне руководства пользователя — в [9]. В системе MISS в среде MS-DOS реализована система программирования на специальном декларативном языке описания сложных систем, интегрированная с базой данных, системой поддержки выполнения модели и системой презентации результатов моделирования. В качестве императивных языков программирования, на которых написаны вычислительные алгоритмы, разрешены две версии языка MODULA-2, а также языки С и С++ в Борландовской реализации. До этого моделирующее сообщество в основном создавало языки моделирования императивного типа.

Впоследствии идея разделения описания сложной системы на декларативную и императивную части применялась неоднократно. Так, в спецификации архитектуры верхнего уровня (High Level Architecture — HLA) [10] — средстве создания сложных распределенных моделей — устройство системы, ее компонент и связей между ними описывается специальными шаблонами. В коммерчески успешной отечественной инструментальной системе имитационного моделирования AnyLogic [11] в качестве декларативного языка описания сложной системы применяется интерактивная графическая система с отображением на экране пиктограмм компонент будущей системы и построением связей между ними. В качестве императивного языка программирования для системы AnyLogic используется язык Java. Наконец, появился и даже стал международным стандартом язык моделирования объектных систем UML [12], однако авторам настоящей статьи он не симпатичен в силу своей громоздкости и, порой, за счет этого — неоднозначности. В качестве результатов компиляции транслятор UML может выдавать заготовки модулей для императивных языков.

В настоящее время в ВЦ РАН продолжает развиваться концепция разделения описания сложной системы на декларативную и императивную составляющие; работает макет инструментальной системы распределенного моделирования. Некоторое затруднение вызывает название этой концепции — такие названия, как агент, актор и даже компонента уже заняты, и в программистском сообществе под ними понимают вполне определенные и отличные от описанного выше подходы. Сами разработчики концепции в работах [7—9, 13—15] называли свой подход объектным или объектно-событийным, что тоже не совсем верно, так как не отражает главных его моментов — наличия поведения у компоненты и декомпозицию описания сложной системы на декларативную и императивную составляющие.

Концепция описания модели [6] базируется на понятии компоненты. Компонента — в некотором смысле «элементарная» сложная система. Основой конструкции компоненты служит объект объектно-

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

1. Характеристики. Компонента, как и объект, имеет характеристики. Эти характеристики разобьем на внутренние и внешние. К внутренним относятся характеристики, которые компонента моделирует, к внешним — информация о внешнем мире.

2. Процессы. Функциональность компоненты удобно структурировать следующим образом. Считается, что компонента реализует один или несколько параллельно выполняющихся процессов. Процесс состоит в последовательном чередовании элементов — алгоритмически элементарных методов. Если какой-либо процесс какую-то часть модельного времени не выполняется, удобно считать, что в это время он выполняет «пустой» элемент, не изменяющий никаких характеристик компоненты.

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

По отношению к модельному времени некоторые элементы (сосредоточенные или быстрые) выполняются мгновенно. Быстрыми элементами можно моделировать дискретные характеристики системы. Выполнение других элементов занимает определенное время. Если при этом элемент для любого промежутка времени Лт, не превосходящего стандартный шаг моделирования Л1, выдает некий осмысленный результат, такой элемент называют распределенным или медленным. Распределенные элементы — естественное средство вычисления непрерывных характеристик модели.

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

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

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

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

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

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

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

если его еще не нужно заканчивать, но он вычислил характеристики компоненты, которые могут повлечь смену элементов других процессов. Процесс перехода должен быть однозначным. Одновременное наступление событий Е{А В} и Е{А С} свидетельствует лишь о том, что

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

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

Правила запуска компоненты на выполнение следующие. Во-первых, задают стандартный шаг моделирования Лt. Во-вторых, полагают, что в начале шага моделирования известны текущие элементы всех процессов и все внутренние и внешние характеристики модели. Далее с помощью специализированной программы:

1) вычисляются события, связанные с текущими элементами процессов. Если есть наступившие события, проверяется, нет ли переходов к быстрым (сосредоточенным) элементам, если они есть — выполняются быстрые элементы (они становятся текущими), затем осуществляется возврат к началу п. 1; если нет переходов к быстрым элементам, совершаются переходы к новым медленным (распределенным) элементам, затем возврат к п. 1;

2) если нет наступивших событий, из всех прогнозируемых событий выбирается ближайшее с шагом Лт;

3) если стандартный шаг моделирования не превосходит прогнозируемого времени до ближайшего события, Лt <Лт, рассчитываются текущие распределенные элементы со стандартным шагом ДЛ В противном случае, они вычисляются с шагом Лт до ближайшего спрогнозированного события;

4) процесс вычислений возвращается к п. 1.

Приведенные правила выполнения компоненты могут вызывать такие вопросы, как не может ли выполнение быстрых элементов в п. 1, а также уменьшение шага времени в п. 3 привести к зациклива-

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

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

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

какие компоненты и в каком количестве экземпляров в него входят;

коммутацию компонент внутри комплекса, если она имеет место, т. е. внутренние переменные каких компонент являются внешними переменными и каких именно компонент комплекса.

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

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

внутренние переменные комплекса — объединение внутренних переменных всех его компонент;

процессы комплекса — объединение всех процессов его компонент;

методы комплекса — объединение всех методов его компонент;

события комплекса — объединение всех событий его компонент;

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

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

Для описания состава и устройства сложной системы разработан специальный декларативный язык ЯОКК (язык описания комплексов и компонент), который развит в сторону упрощения языка MISS [9] и описан в [6, 13].

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

Еще одна область имитационного моделирования, в которой могут применяться декларативные описания, — область подготовки презентаций результатов моделирования. Языки описания подобных презентаций неизвестны, однако необходимость в них явно имеется. При этом самое простое, но тем не менее весьма полезное, что можно сделать, — по таблице-выборке из базы данных строить диаграммы, как в MS Excel или в OpenOffice Calc. Возможно также применение популярных в последнее время геоинформационных систем — отображение пиктограммами на интересующей карте динамики перемещения моделируемых объектов. И наконец, использование простейшей анимации в стиле Flash-морфинг форм и перемещение объектов с возможным изменением размеров. Более серьезная анимация пока остается прерогативой компьютерных игр.

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

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

Работа выполнена при финансовой поддержке РФФИ (грант № 10-07-00176) и РГНФ (ггрант № 12-06-00932).

СПИСОК ЛИТЕРАТУРЫ

1. Zave P. A compositional approach to multiparadigm programming. IEEE Software, 6(5): 15—25, September 1989.

2. Бусленко Н. П. Моделирование сложных систем. М.: Наука, 1978.

3. H e w i t t C. Viewing Control Structures as Patterns of Passing Messages Journal of Artificial Intelligence. June 1977.

4. S hoham Y. Agent-oriented programming // Artificial Intelligence. Vol. 60, 1993. P. 51-92.

5. S hoham Y. MULTIAGENT SYSTEMS: Algorithmic, Game-Theoretic, and Logical Foundations Cambridge: Cambridge University Press, 2010.

6. Бродский Ю. И. Распределенное имитационное моделирование сложных систем. М.: ВЦ РАН, 2010.

7. Бродский Ю. И., Лебедев В. Ю., Огарышев В. Ф., Павловский Ю. Н., Савин Г. И. Общие проблемы моделирования сложных организационно-технических систем // Вопросы кибернетики. Проблемы математического моделирования и экспертные системы. М.: Научный совет АН СССР по комплексной проблеме «Кибернетика», 1990. С. 42-48.

8. Бродский Ю. И., Лебедев В. Ю. Инструментальная система для построения имитационных моделей хорошо структурированных организационно-технических комплексов // Вопросы кибернетики. Проблемы математического моделирования и экспертные системы, М.: Научный совет АН СССР по комплексной проблеме «Кибернетика», 1990. С. 49-64.

9. Бродский Ю. И., ЛебедевВ. Ю. Инструментальная система имитации MISS. М.: ВЦ АН СССР, 1991.

10. Kuhl F., Weatherly R., Dahmann J. Creating Computer Simulation Systems: An Introduction to the High Level Architecture NY: Prentice Hall PTR, 1999.

11. Осоргин А. Е. AnyLogic 6. Лабораторный практикум. Самара: ПГК, 2011.

12. Буч Г., Рамбо Дж., Джекобсон А. Язык UML. Руководство пользователя. 2-е изд. М.; СПб.: ДМК Пресс, Питер, 2004.

13. B r o d s k y Y. Simulation Software // System Analysis and Modeling of Intergrated Word Systems. V. 1, Oxford: EOLSS Publishers Co. Ltd., 2009. P. 287-298.

14. B r o d s k y Y., T o k a r e v V. Fundamentals of simulation for complex systems. // System Analysis and Modeling of Integrated World Systems. V. 1, Oxford: EOLSS Publishers Co. Ltd., 2009. P. 235-250.

15. Бродский Ю. И., Павловский Ю. Н. Разработка инструментальной системы распределенного имитационного моделирования // Информационные технологии и вычислительные системы. 2009. № 4. С. 9-21.

Статья поступила в редакцию 03.07.2012.

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

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

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

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

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

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

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




ДРУГИЕ ЯЗЫКИ

Functional programming vs. imperative programming — LINQ to XML



  • Чтение занимает 3 мин

В этой статье

This article compares and contrasts functional programming with more traditional imperative (procedural) programming.

Functional programming vs. imperative programming

The functional programming paradigm was explicitly created to support a pure functional approach to problem solving. Functional programming is a form of declarative programming. In contrast, most mainstream languages, including object-oriented programming (OOP) languages such as C#, Visual Basic, C++, and Java, were designed to primarily support imperative (procedural) programming.

With an imperative approach, a developer writes code that specifies the steps that the computer must take to accomplish the goal. This is sometimes referred to as algorithmic programming. In contrast, a functional approach involves composing the problem as a set of functions to be executed. You define carefully the input to each function, and what each function returns. The following table describes some of the general differences between these two approaches.

Characteristic Imperative approach Functional approach
Programmer focus How to perform tasks (algorithms) and how to track changes in state. What information is desired and what transformations are required.
State changes Important. Non-existent.
Order of execution Important. Low importance.
Primary flow control Loops, conditionals, and function (method) calls. Function calls, including recursion.
Primary manipulation unit Instances of structures or classes. Functions as first-class objects and data collections.

Although most languages were designed to support a specific programming paradigm, many general languages are flexible enough to support multiple paradigms. For example, most languages that contain function pointers can be used to credibly support functional programming. Furthermore, C# and Visual Basic include explicit language extensions to support functional programming, including lambda expressions and type inference. LINQ technology is a form of declarative, functional programming.

Functional programming using XSLT

Many XSLT developers are familiar with the pure functional approach. The most effective way to develop an XSLT style sheet is to treat each template as an isolated, composable transformation. The order of execution is completely de-emphasized. XSLT doesn’t allow side effects (with the exception that escaping mechanisms for executing procedural code can introduce side effects that result in functional impurity). However, although XSLT is an effective tool, some of its characteristics aren’t optimal. For example, expressing programming constructs in XML makes code relatively verbose, and therefore difficult to maintain. Also, the heavy reliance on recursion for flow control can result in code that’s hard to read. For more information about XSLT, see XSLT Transformations.

However, XSLT has proved the value of using a pure functional approach for transforming XML from one shape to another. Pure functional programming with LINQ to XML is similar in many ways to XSLT. However, the programming constructs introduced by LINQ to XML, C#, and Visual Basic allow you to write pure functional transformations that are more readable and maintainable than XSLT.

Advantages of pure functions

The primary reason to implement functional transformations as pure functions is that pure functions are composable: that is, self-contained and stateless. These characteristics bring a number of benefits, including the following:

  • Increased readability and maintainability. This is because each function is designed to accomplish a specific task given its arguments. The function doesn’t rely on any external state.
  • Easier reiterative development. Because the code is easier to refactor, changes to design are often easier to implement. For example, suppose you write a complicated transformation, and then realize that some code is repeated several times in the transformation. If you refactor through a pure method, you can call your pure method at will without worrying about side effects.
  • Easier testing and debugging. Because pure functions can more easily be tested in isolation, you can write test code that calls the pure function with typical values, valid edge cases, and invalid edge cases.

Transitioning for OOP developers

In traditional object-oriented programming (OOP), most developers are accustomed to programming in the imperative/procedural style. To switch to developing in a pure functional style, they have to make a transition in their thinking and their approach to development.

To solve problems, OOP developers design class hierarchies, focus on proper encapsulation, and think in terms of class contracts. The behavior and state of object types are paramount, and language features, such as classes, interfaces, inheritance, and polymorphism, are provided to address these concerns.

In contrast, functional programming approaches computational problems as an exercise in the evaluation of pure functional transformations of data collections. Functional programming avoids state and mutable data, and instead emphasizes the application of functions.

Fortunately, C# and Visual Basic don’t require the full leap to functional programming, because they support both imperative and functional programming approaches. A developer can choose which approach is most appropriate for a particular scenario. In fact, programs often combine both approaches.

See also

Стр. 1 — Ю.И. Бродский, А.Н. Мягков


ISSN 1812-3368. Вестник МГТУ им. Н.Э. Баумана. Сер. «Естественные науки». 2012


178


УДК 519.87


Ю. И. Б р о д с к и й , А. Н. Мя г к о в



ДЕКЛАРАТИВНОЕ И ИМПЕРАТИВНОЕ



ПРОГРАММИРОВАНИЕ В ИМИТАЦИОННОМ



МОДЕЛИРОВАНИИ СЛОЖНЫХ



МНОГОКОМПОНЕНТНЫХ СИСТЕМ


Изложены подходы к моделированию таких сложных систем, про


которые хорошо известно, из каких компонент они состоят


,


ка-


кие функции эти компоненты выполняют


,


по каким правилам вза-


имодействуют между собой. Проблема моделирования


,


причем


весьма непростая


,


заключается в воспроизведении поведения и


оценке возможностей такой системы в целом. Рассмотрены во-


просы эффективности применения различных парадигм програм-


мирования для решения задачи синтеза многокомпонентной си-


стемы.



Е-mail:




Ключевые слова



:


имитационное моделирование, сложные системы,


парадигмы программирования, поведение системы, объектно-ориенти-


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


.


Под императивным программированием понимают распростра-


ненный подход к написанию программ на языках программирования


типа FORTRAN, семейства С или Java, согласно которому программа


представляет собой последовательность инструкций-приказов, вы-


полняемых на компьютере. Использование императивного програм-


мирования позволяет описать последовательность действий, доста-


точную (на взгляд разработчика) для получения результата постав-


ленной задачи. При этом не предполагается, что результат заранее


известен, и скорее всего цель императивного программирования со-


стоит в получении этого результата (например, численное решение


системы уравнений в частных производных или изучение поведения


сложной системы в имитационном эксперименте с ее моделью). Бо-


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


говоря, удивляет и поражает своих создателей.


При декларативном программировании, наоборот, описывают,


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


мер, статическая страничка HTML, документ в системе LaTeX или


DVD-проект в системе авторинга Scenarist. При этом выбор последо-


вательности действий, приводящей в системе декларативного про-


МОДЕЛИРОВАНИЕ СОЦИАЛЬНО-


ЭКОНОМИЧЕСКИХ ПРОЦЕССОВ

définition de %d0%98%d0%bc%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%b8%d0%b2%d0%bd%d0%be%d0%b5%20%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5 et synonymes de %d0%98%d0%bc%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%b8%d0%b2%d0%bd%d0%be%d0%b5%20%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5 (russe)



%d0%98%d0%bc%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%b8%d0%b2%d0%bd%d0%be%d0%b5%20%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5 : définition de %d0%98%d0%bc%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%b8%d0%b2%d0%bd%d0%be%d0%b5%20%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5 et synonymes de %d0%98%d0%bc%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%b8%d0%b2%d0%bd%d0%be%d0%b5%20%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5 (russe)

Contenu de sensagent

  • définitions
  • synonymes
  • antonymes
  • encyclopédie
  • определение
  • синоним

dictionnaire et traducteur pour sites web

Alexandria

Une fenêtre (pop-into) d’information (contenu principal de Sensagent) est invoquée un double-clic sur n’importe quel mot de votre page web. LA fenêtre fournit des explications et des traductions contextuelles, c’est-à-dire sans obliger votre visiteur à quitter votre page web !

Essayer ici, télécharger le code;

Solution commerce électronique

Augmenter le contenu de votre site

Ajouter de nouveaux contenus Add à votre site depuis Sensagent par XML.

Parcourir les produits et les annonces

Obtenir des informations en XML pour filtrer le meilleur contenu.

Indexer des images et définir des méta-données

Fixer la signification de chaque méta-donnée (multilingue).

Renseignements suite à un email de description de votre projet.

Lettris

Lettris est un jeu de lettres gravitationnelles proche de Tetris. Chaque lettre qui apparaît descend ; il faut placer les lettres de telle manière que des mots se forment (gauche, droit, haut et bas) et que de la place soit libérée.

boggle

Il s’agit en 3 minutes de trouver le plus grand nombre de mots possibles de trois lettres et plus dans une grille de 16 lettres. Il est aussi possible de jouer avec la grille de 25 cases. Les lettres doivent être adjacentes et les mots les plus longs sont les meilleurs. Participer au concours et enregistrer votre nom dans la liste de meilleurs joueurs ! Jouer

Dictionnaire de la langue française
Principales Références

La plupart des définitions du français sont proposées par SenseGates et comportent un approfondissement avec Littré et plusieurs auteurs techniques spécialisés.
Le dictionnaire des synonymes est surtout dérivé du dictionnaire intégral (TID).
L’encyclopédie française bénéficie de la licence Wikipedia (GNU).

Traduction

Changer la langue cible pour obtenir des traductions.
Astuce: parcourir les champs sémantiques du dictionnaire analogique en plusieurs langues pour mieux apprendre avec sensagent.

 

9177 visiteurs en ligne

calculé en 0,530s

allemand
anglais
arabe
bulgare
chinois
coréen
croate
danois
espagnol
espéranto
estonien
finnois
français
grec
hébreu
hindi
hongrois
islandais
indonésien
italien
japonais
letton
lituanien
malgache
néerlandais
norvégien
persan
polonais
portugais
roumain
russe
serbe
slovaque
slovène
suédois
tchèque
thai
turc
vietnamien

allemand
anglais
arabe
bulgare
chinois
coréen
croate
danois
espagnol
espéranto
estonien
finnois
français
grec
hébreu
hindi
hongrois
islandais
indonésien
italien
japonais
letton
lituanien
malgache
néerlandais
norvégien
persan
polonais
portugais
roumain
russe
serbe
slovaque
slovène
suédois
tchèque
thai
turc
vietnamien

Сравнение функционального программирования и императивного программирования — LINQ to XML

  • 3 минуты на чтение

В этой статье

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

Сравнение функционального программирования и императивного программирования

Функциональное программирование Парадигма была явно создана для поддержки чисто функционального подхода к решению проблем.Функциональное программирование — это форма декларативного программирования . Напротив, большинство основных языков, включая языки объектно-ориентированного программирования (ООП), такие как C #, Visual Basic, C ++ и Java, были разработаны, в первую очередь, для поддержки императивного программирования (процедурного).

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

Характеристика Императивный подход Функциональный подход
Программист фокус Как выполнять задачи (алгоритмы) и как отслеживать изменения состояния. Какая информация требуется и какие преобразования требуются.
Изменения состояния Важно. Не существует.
Порядок исполнения Важно. Низкая важность.
Контроль первичного потока Циклы, условные выражения и вызовы функций (методов). Вызовы функций, включая рекурсию.
Первичный манипулятор Экземпляры структур или классов. Функционирует как первоклассные объекты и коллекции данных.

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

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

Многие разработчики XSLT знакомы с чисто функциональным подходом. Самый эффективный способ разработки таблицы стилей XSLT — рассматривать каждый шаблон как изолированное, составное преобразование. Совершенно не акцентируется порядок исполнения. XSLT не допускает побочных эффектов (за исключением того, что механизмы экранирования для выполнения процедурного кода могут вызвать побочные эффекты, которые приводят к функциональной нечистоте).Однако, хотя XSLT — эффективный инструмент, некоторые его характеристики не оптимальны. Например, выражение программных конструкций в XML делает код относительно многословным, и поэтому его трудно поддерживать. Кроме того, сильная зависимость от рекурсии для управления потоком может привести к тому, что код будет трудно читать. Для получения дополнительных сведений о XSLT см. Преобразования XSLT.

Однако XSLT доказал ценность использования чисто функционального подхода для преобразования XML из одной формы в другую. Чистое функциональное программирование с LINQ to XML во многом похоже на XSLT.Однако программные конструкции, представленные LINQ to XML, C # и Visual Basic, позволяют писать чисто функциональные преобразования, которые более удобочитаемы и удобнее, чем XSLT.

Преимущества чистых функций

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

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

Переход для разработчиков ООП

В традиционном объектно-ориентированном программировании (ООП) большинство разработчиков привыкли программировать в императивном / процедурном стиле. Чтобы перейти к разработке в чисто функциональном стиле, они должны изменить свое мышление и подход к разработке.

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

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

К счастью, C # и Visual Basic не требуют полного перехода к функциональному программированию, поскольку они поддерживают как императивный, так и функциональный подходы к программированию. Разработчик может выбрать наиболее подходящий подход для конкретного сценария. На самом деле программы часто сочетают оба подхода.

См. Также

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

К

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

Императивное программирование требует понимания функций, необходимых для решения проблемы, а не использования моделей, которые могут ее решить. Основное внимание в императивном программировании уделяется способам решения проблемы, для чего требуется подробное пошаговое руководство. Поскольку написанный код выполняет функции вместо моделей, программист должен кодировать каждый шаг.Языки процедурного и объектно-ориентированного программирования (ООП) подпадают под императивное программирование, например C, C ++, C # и Java.

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

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

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

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

Последнее обновление: ноябрь 2018 г.


Продолжить чтение об императивном программировании

Терминология

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

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

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

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

Определение декларативного выражения

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

100% декларативный язык (то есть язык, на котором каждое возможное выражение — это RT) не допускает (среди других требований RT) изменение сохраненных значений, например HTML и большая часть Haskell.

Определение выражения RT

RT часто называют «без побочных эффектов». Термин эффекты не имеет точного определения, поэтому некоторые люди не согласны с тем, что «отсутствие побочных эффектов» — это то же самое, что RT.RT имеет точное определение:

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

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

Определение чистой функции

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

Чистые функции имеют следующие атрибуты.

  • единственный наблюдаемый вывод — это возвращаемое значение.
  • единственная выходная зависимость — это аргументы.
  • аргумента полностью определяются до создания любого вывода.

Помните, что RT применяется к выражениям (включая вызовы функций), а чистота применяется к (реализациям) функций.

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

Производные атрибуты РТ

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

Обратите внимание, неизменность внешних значений является подмножеством требований для RT.

  • Декларативные языки не имеют структур управления циклами, например для и , а , поскольку из-за неизменности условие цикла никогда не изменится.

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

  • Декларативные языки выражают логические «шаги» (т. Е. Порядок вызова вложенных функций RT), но является ли каждый вызов функции семантикой более высокого уровня (т. Е. «Что делать») не является требованием декларативного программирования. Отличие от императива в том, что из-за неизменности (то есть в более общем смысле RT) эти «шаги» не могут зависеть от изменяемого состояния, а только от реляционного порядка выраженной логики (т.е.е. порядок вложения вызовов функций, также называемых подвыражениями).

Например, абзац HTML

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

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

Заказ на оценку

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

Например, для некоторых вложенных выражений, например f (g (a, b), h (c, d)) , нетерпеливое и ленивое вычисление аргументов функции даст те же результаты, если функции f , g и h являются чистыми.

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

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

Тангенциально, если все идентификаторы, например a , b , c , d , неизменяемы везде, состояние, внешнее по отношению к программе, недоступно (т.е.е. I / O), и нет разрыва уровня абстракции, тогда функции всегда чистые.

Кстати, у Haskell другой синтаксис: f (g a b) (h c d) .

Детали оценочного заказа

Функция — это переход состояния (не изменяемое сохраненное значение) от входа к выходу. Для композиций RT из вызовов чистых функций порядок выполнения этих переходов состояний не зависит. Переход состояния каждого вызова функции не зависит от других из-за отсутствия побочных эффектов и принципа, согласно которому функция RT может быть заменена ее кэшированным значением.Чтобы исправить распространенное заблуждение, чистая монадическая композиция всегда декларативна, а RT , несмотря на то, что монада IO в Haskell, возможно, нечистая и, следовательно, императивная относительно w.r.t. состояние World внешнее по отношению к программе (но в смысле предупреждения ниже побочные эффекты изолированы).

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

Определение : параметры функции объявлены на сайте определения функции , а аргументы функции предоставляются на сайте вызова функции . Знайте разницу между параметром и аргументом .

Концептуально все выражения являются (составом) вызовов функций, например константы — это функции без входов, унарные операторы — это функции с одним входом, двоичные инфиксные операторы — это функции с двумя входами, конструкторы — это функции и даже управляющие операторы (например,грамм. , если , для , , а ) можно моделировать с помощью функций. Порядок, в котором оцениваются эти функции аргумента (не путать с порядком вызова вложенных функций), не объявлен синтаксисом, например f (g ()) может нетерпеливо оценить g , затем f на результате g , или он может оценить f и только лениво оценить g , когда его результат требуется в пределах f .

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

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

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

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

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

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

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

Параллельность

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

Принцип Брента: вычисления с работой w и глубиной d могут быть
реализовано в PRAM p-процессора за время O (max (w / p, d)).

Как параллелизм, так и параллелизм также требуют декларативного программирования, то есть неизменяемости и RT.

Так откуда взялось это опасное предположение, что Parallelism == Concurrency
родом из? Это естественное следствие языков с побочными эффектами:
когда у вашего языка везде есть побочные эффекты, тогда каждый раз, когда вы пытаетесь
делать больше чем одно дело за раз
недетерминизм, вызванный чередованием эффектов от каждого
операция. Итак, в языках с побочными эффектами единственный способ получить
параллелизм — это параллелизм; поэтому неудивительно, что мы
часто видят, что эти два соединены.

Заказ на оценку FP

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

Нетерпеливый (CBV) и ленивый (CBN) являются категориальными дуэлями [10], потому что они имеют обратный порядок оценки, то есть, сначала оцениваются внешние или внутренние функции соответственно. Представьте себе перевернутое дерево, а затем нетерпеливые вычисления от ветвей дерева функций вверх по иерархии ветвей к стволу функции верхнего уровня; тогда как ленивый оценивает от ствола до кончиков веток.У нетерпеливого нет конъюнктивных продуктов («и», a / k / a категориальные «продукты»), а у ленивого нет дизъюнктивных сопутствующих продуктов («or», a / k / a категориальные «суммы») [11].

Производительность

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

Эта ненужная работа является причиной заявленного «до» дополнительного коэффициента log n в последовательной временной сложности между нетерпеливым и ленивым как с чистыми функциями. Решение состоит в том, чтобы использовать функторы (например, списки) с ленивыми конструкторами (т. Е. С необязательными ленивыми продуктами), потому что с нетерпением некорректность происходит от внутренней функции. Это связано с тем, что продукты являются конструктивными типами, то есть индуктивными типами с начальной алгеброй на начальной фиксированной точке [11]

Как и в случае с незавершением, ленивый слишком ленив с дизъюнктивной функциональной композицией, т.е.е. Коиндуктивная завершенность может произойти позже, чем необходимо, что приведет как к ненужной работе, так и к недетерминированности опозданий, чего не бывает с нетерпеливым [10] [11]. Примерами окончательности являются исключения состояния, времени, незавершенности и времени выполнения. Это императивные побочные эффекты, но даже в чистом декларативном языке (например, Haskell) в императивной монаде ввода-вывода есть состояние (примечание: не все монады императивные!), Неявное в распределении пространства, а время — это состояние относительно императивного реальный мир.Использование lazy даже с необязательным нетерпеливым сопродуктом приводит к утечке «лени» во внутренние сопутствующие продукты, потому что с lazy некорректность лени возникает из внешней функции (см. Пример в разделе «Без завершения», где == — внешняя бинарная операторная функция). Это связано с тем, что копроизведения ограничены конечностью, т. Е. Коиндуктивными типами с конечной алгеброй на конечном объекте [11].

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

Прекращение действия

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

С нетерпением, но не ленивым, для соединения Head «и» Tail , если либо Head , либо Tail не завершаются, то соответственно либо List (Head (), Tail ()).tail == Tail () или List (Head (), Tail ()) .head == Head () неверно, потому что левая сторона не завершается, а правая завершается.

Тогда как у ленивых обе стороны оканчиваются. Таким образом, компания eager слишком увлечена конъюнктивными продуктами и не завершается (включая исключения времени выполнения) в тех случаях, когда в этом нет необходимости.

С ленивым, но не нетерпеливым, для дизъюнкции 1 «или» 2 , если f не завершается, тогда List (f? 1: 2, 3).tail == (f? List (1, 3): List (2, 3)). tail неверно, потому что левая сторона завершается, а правая — нет.

Принимая во внимание, что с нетерпением ни одна из сторон не завершает работу, поэтому тест на равенство никогда не достигается. Таким образом, lazy слишком ленив с дизъюнктивными сопутствующими продуктами, и в этих случаях не удается завершить работу (включая исключения времени выполнения) после выполнения большей работы, чем было бы у eager.

[10] Декларативные продолжения и категориальная двойственность, Филински, разделы 2.5.4 Сравнение CBV и CBN, и 3.6.1 CBV и CBN в SCL.

[11] Декларативные продолжения и категориальная двойственность, Филински, разделы 2.2.1 Продукты и сопродукты, 2.2.2 Конечные и начальные объекты, 2.5.2 CBV с ленивыми продуктами и 2.5.3 CBN с нетерпеливыми копродукциями.

Императивное и декларативное программирование — ui.dev

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

«Вы знаете, императивное программирование — это , , как вы что-то делаете, а декларативное программирование — это скорее , , что вы делаете, или что-то в этом роде.”

Это определение имеет смысл, если вы действительно знаете разницу между императивом и декларативностью, но вы этого не знаете, поэтому вы задали этот вопрос в первую очередь. Это все равно, что пытаться ответить: «Что было раньше, курица или яйцо?» за исключением того, что все, кажется, думают, что курица любила, но вы даже не любите яйца и запутались. Объедините это разочарование с бессмысленным употреблением слова «декларативный», чтобы в основном означать просто «хорошо», и внезапно ваш синдром самозванца стал чечеткой на вашей уверенности, и вы поймете, что вам даже не нравится программировать.Но не волнуйся, друг. Я не знаю, что такое монада, поэтому, надеюсь, этот пост поможет вам понять, что декларативность — это больше, чем просто «легко рассуждать» и «хорошо».

Самое сложное в этой теме, как заметил Меррик: «Это одна из тех вещей, о которых вы догадываетесь, но не можете объяснить». Я разговаривал со многими разработчиками, и мне кажется, что больше всего помогает сочетание метафор с реальными примерами кода. Так что пристегнитесь, потому что я собираюсь проповедовать.

Давайте вернемся к первоначальному определению, которое я высмеивал над

«Императивное программирование похоже на , как вы что-то делаете, а декларативное программирование больше похоже на на то, что вы
делать.”

На самом деле здесь спрятано НЕКОТОРЫЕ хорошей информации. Давайте сначала рассмотрим достоинства этого определения, вырвав его из контекста программирования и посмотрев на пример из «реальной жизни».

Вы решили, что потратили слишком много времени на споры о «Усталости от JavaScript» ™, и ваш муж заслуживает приятного свидания. Вы решили пойти в Red Lobster, так как в последнее время много слушаете Бейонсе (👑🐝). Вы приезжаете в Red Lobster, подходите к стойке регистрации и говорите…

Повелительный подход (КАК) : «Я вижу, что таблица, расположенная под знаком Gone Fishin», пуста.Мы с мужем собираемся пойти туда и сесть ».

Декларативный подход (ЧТО) : «Стол на двоих, пожалуйста».

Императивный подход связан с КАК вы на самом деле собираетесь получить место. Вам нужно перечислить шаги, чтобы показать HOW , что вы собираетесь получить стол. Декларативный подход больше связан с WHAT you want, таблицей на двоих.

«Хорошо.» — ваш мозг

Больше метафор!

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

«Я рядом с Wal-Mart. Как мне отсюда добраться до твоего дома? »




Императивная реакция : Выйдите из северного выхода с парковки и поверните налево. Двигайтесь по I-15 North, пока не дойдете до съезда с 12-й улицы. Сверните направо с выезда, как будто собираетесь в Икеа. Идите прямо и на первом светофоре поверните направо. Продолжайте движение к следующему светофору, затем поверните налево.Мой дом № 298.

Декларативный ответ : Мой адрес: 298 West Immutable Alley, Eden, Utah 84310

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


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

  • Декларативный ответ сотруднику Red Lobster («столик на двоих, пожалуйста») предполагает, что сотрудник Red Lobster знает все необходимые шаги, чтобы привести нас к столу.
  • Знание адреса предполагает, что у вас есть какой-то GPS, который знает, как добраться до вашего дома.
  • У автомобиля с автоматической коробкой передач есть своего рода слой абстракции над переключением передач.

Это осознание меня действительно поразило, поэтому я повторю:

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

Если это предложение имеет смысл, у вас все отлично!


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

Императив : C, C ++, Java

Декларативная : SQL, HTML

(Может быть) Смешайте : JavaScript, C #, Python


Подумайте о типичном примере SQL или HTML,

  ВЫБРАТЬ * ИЗ пользователей ГДЕ Страна = 'Мексика';  
  <статья>
  <заголовок>
    

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

Добавьте декларативность в свое словоблудие, чтобы звучало умно

Глядя на оба примера, вы ясно понимаете, что происходит.Оба они декларативны. Их интересует ЧТО, , вы хотите сделать, а не КАК, , вы хотите, чтобы это было сделано.

Вы описываете, чего пытаетесь достичь, но не инструктируете, как это сделать. Реализация выбора всех пользователей, проживающих в Мексике, была отвлечена от вас. Вас не волнует, как веб-браузер анализирует ваш элемент article и отображает его на экране. Ваш ЧТО — это мексиканских пользователей или новый заголовок и абзац на вашем веб-сайте.

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


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

  1. Напишите функцию с именем double , которая принимает массив чисел и возвращает новый массив после удвоения каждого элемента в этом массиве. двойной ([1,2,3]) // [2,4,6]
  2. Напишите функцию с именем add , которая принимает массив и возвращает результат сложения каждого элемента в массиве. add ([1,2,3]) // 6
  3. Используя jQuery (или ванильный JavaScript), добавьте обработчик события click к элементу, который имеет id из btn . При нажатии переключите (добавьте или удалите) класс выделения , а также измените текст на Добавить выделение или Удалить выделение в зависимости от текущего состояния элемента.

Давайте посмотрим на наиболее распространенные подходы к этим проблемам, которые также являются императивными подходами.

  function double (arr) {
  let results = []
  for (let i = 0; i  
  function add (arr) {
  пусть результат = 0
  for (let i = 0; i  
  $ ("# btn"). Click (function () {
  $ (это) .toggleClass ("выделение")
  $ (this) .text () === 'Добавить выделение'
    ? $ (this) .text ('Убрать выделение')
    : $ (this) .text ('Добавить выделение')
})  

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

  1. Наиболее очевидной общностью является то, что они описывают КАК что-то делать. В каждом примере мы либо явно перебираем массив, либо явно описываем шаги по реализации желаемой функциональности.
  2. Это может быть не так очевидно, если вы не привыкли мыслить в духе декларативного или, более конкретно, функционального . В каждом примере мы изменяем некоторую часть состояния (если вы не знакомы с термином «состояние», это, по сути, информация о чем-то, хранящемся в памяти, которая должна звучать как переменные).В первых двух примерах мы создаем переменную с именем results, а затем постоянно ее изменяем. В третьем примере у нас нет никаких переменных, но у нас все еще есть состояние, живущее в самой DOM - затем мы изменяем это состояние в DOM.
  3. Это немного субъективно, но для меня приведенный выше код не очень удобочитаем. Я не могу просто взглянуть на код и понять, что происходит. Мой мозг должен пройти через код точно так же, как это сделал бы интерпретатор, при этом принимая во внимание контекст, в котором живет код (еще один негативный фактор изменяемых данных).

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

  function double (arr) {
  вернуть arr.map ((item) => item * 2)
}  
  function add (arr) {
  вернуть arr.reduce ((предыдущая, текущая) => предыдущая + текущая, 0)
}  
  
    {this.state.buttonText}
  

Намного лучше

🤓

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

В каждом примере мы описываем ЧТО мы хотим, а не КАК (мы не знаем, КАК реализованы map и reduce, нам также, вероятно, все равно).Мы не изменяем ни одно состояние. Все мутации абстрагируются внутри карты и уменьшить . Кроме того, он более читабелен (как только вы привыкнете к карте , и , конечно, уменьшат ).

А как насчет последнего примера? Ну, я немного схитрил и использую React, но учтите, что все три обязательные ошибки все еще исправлены. Настоящая прелесть React в том, что вы можете создавать декларативные пользовательские интерфейсы. Глядя на наш компонент Btn , я могу быстро понять, как будет выглядеть пользовательский интерфейс.Еще одно преимущество заключается в том, что вместо состояния, живущего в DOM, оно живет в самом компоненте React.

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

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


Я не стал вдаваться в подробности: функциональное программирование является подмножеством декларативного программирования. Если вы еще этого не сделали, я настоятельно рекомендую поближе познакомиться с методами функционального программирования на JavaScript. Начните с .map , .reduce , .filter и продвигайтесь дальше.Скорее всего, нет более низкого результата для улучшения вашей кодовой базы, чем повышение ее функциональности.


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

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

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

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

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

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

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

Декларативный кодекс в сравнении с императивным | Мартин Новак

Декларативный код очень распространен и представлен предметно-ориентированными языками логического и функционального программирования.Примерами этого являются HTML, SQL, F #, Prolog и Lisp.

Декларативный код фокусируется на выражениях, которые говорят what без добавления how . Например, HTML-код указывает браузеру отображать изображение черепахи, не сообщая браузеру, как это сделать. Также типично, что декларативный код избегает изменения состояния и переменных.

Доменный код

Доменные языки не являются полными по Тьюрингу, что означает, что они не могут делать все, что могут другие полные по Тьюрингу языки.Например, C # (императивный) и F # (декларативный) являются языками для превращения, и все, что вы можете разработать в одном, вы также можете разрабатывать в другом. HTML не является полным по Тьюрингу и позволяет делать только определенные вещи.

Пример кода SQL, который находит сотрудников и их менеджеров в базе данных:

Доменные языки обычно очень просты для написания и чтения. По этой причине они являются наиболее популярным способом объявления пользовательского интерфейса. Например, библиотека программирования JavaScript React использует JSX для определения компонентов:

Примерами предметно-ориентированных языков являются SQL (1974), HTML (1993), CSS (1996) и XML (1996).

Логический код

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

Наиболее типичным языком логического программирования, полным по Тьюрингу, является Prolog (1972). Это означает, что все, что вы можете написать на языке C, вы теоретически можете написать и на Prolog.

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

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

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

Пролог - это своего рода волшебство, когда вы работаете в нем, и если вы не согласны, то вы все равно злой детоед.

Функциональный код

Функциональное программирование - это декларативная парадигма, основанная на композиции чистых функций.Языки функционального программирования являются полными по Тьюрингу и основаны на лямбда-исчислении, которое представляет собой систему математической логики 1930-х годов.

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

Функциональное программирование неуклонно набирает популярность в последние годы, и оно проникло в императивные языки программирования.Это означает, что такие языки, как Python, C ++ и JavaScript, являются мультипарадигматическими, поскольку они поддерживают написание кода в нескольких парадигмах.

Вот пример функционального кода, написанного на JavaScript с использованием библиотеки @ 7urtle / lambda:

Функциональное программирование приносит с собой ряд новых концепций, которых нет в объектно-ориентированном программировании, таких как чистые функции, функции высшего порядка, неизменяемость. , функторы, частичное применение, бесточечные функции и т. д. Из-за этого входной барьер может казаться высоким, тем более что многие статьи по функциональному программированию любят очень глубоко углубляться в его математические корни.Я рекомендую ознакомиться с простыми статьями вроде основ функционального программирования @ 7urtle / lambda JavaScript.

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

Другими примерами языков функционального программирования являются LISP (1984), Haskell (1990) и F # (2005).

Декларативное и императивное программирование с использованием SwiftUI и UIKit | Роберт Мехиа | Безупречная iOS

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

В этой статье мы рассмотрим сравнение SwiftUI с некоторыми другими способами создания приложений для экосистемы Apple. В следующей статье мы рассмотрим сравнение React и SwiftUI.

SwiftUI был представлен в WWDC19 и мгновенно покорил сообщество Swift. В течение первых нескольких недель после его выпуска было написано много статей и сняты видеоролики, так как многие разработчики были в восторге от огромного выпуска! SwiftUI позволяет нам объявлять пользовательский интерфейс и поведение нашего приложения на всех различных платформах Apple, что вызывает восхищение!

До SwiftUI у разработчиков был UIKit для приложений iOS и tvOS, AppKit для приложений macOS и WatchKit для watchOS.Эти четыре среды пользовательского интерфейса, управляемых событиями, используют парадигму программирования, известную как императивное программирование.

Согласно Википедии:

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

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

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

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

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

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

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

Основным преимуществом изучения и использования SwiftUI является возможность кроссплатформенной разработки для различных операционных систем в экосистеме Apple. Больше не нужно изучать четыре разных фреймворка, если вы хотите создать приложение, которое имеет компоненты на Apple Watch, Apple TV, MacBook Pro и, наконец, на вашем iPhone.

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

Вот краткий код, который можно использовать для сравнения декларативных и императивных примеров с использованием UIKit для iOS и SwiftUI. Скриншот приложения следует.

Пример приложения

Это простое приложение, которое просто берет имя, введенное пользователем, и добавляет это имя к метке. Несмотря на то, что это простое приложение, оно действительно позволяет увидеть преимущества обоих подходов.Давайте сначала рассмотрим код в UIKit. Наш файл ViewController.swift - это главный файл-ответ для отображения нашего представления.

ViewController.swift - UIKit

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

Заметим, что строки 18 и 22–27 являются наиболее важными для этого поста. Это строки, отвечающие за обновление текстовой метки каждый раз при обновлении текстового поля. Сначала мы должны сказать текстовому полю в строке 18: «Эй, вызовите метод textFieldDidChange, когда значение текстового поля изменилось». Во-вторых, в методе textFieldDidChange мы получаем состояние или значение текстового поля и обновляем текст внутри нашей метки. Изысканный.

Давайте теперь посмотрим на то же представление, написанное с использованием SwiftUI.

ContentView.swift - Swift UI

В этом примере мы видим атрибут @State в строке 2. Он сообщает swift, что ему необходимо обновить свойство name. Строка 6 сообщает swift, что вы обновляете эту переменную с помощью этого текстового поля, но также вы отображаете данные в этой переменной. Следовательно, при обновлении текстового поля изменяется и наша переменная состояния. Это называется двусторонней привязкой. То есть мы используем переменную состояния для отображения данных, но swift также обновляет состояние переменной, когда это необходимо.Наконец, в строке 7 мы привязываем нашу переменную состояния к текстовой метке. Обратите внимание на отсутствие знака доллара, поскольку мы читаем только переменную в этой строке. Обновить нет возможности!

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

За эти абстракции приходится платить. Мы не можем настраивать наши данные так легко, как нам хотелось бы. И снова, где есть воля, там и далеко. Спасибо за чтение!

Введение в императивное программирование | SpringerLink

Abstract

В главе 3 вы увидели некоторые простые, но мощные типы данных и языковые конструкции, составляющие функциональное программирование F #.Парадигма функционального программирования тесно связана с «программированием без побочных эффектов», называемым чистым функциональным программированием. В этой парадигме программы вычисляют результат математического выражения и не вызывают никаких побочных эффектов, за исключением, возможно, сообщения результата вычисления. Формулы, используемые в электронных таблицах, часто чистые, как и ядро ​​языков функционального программирования, таких как Haskell. Однако F # не является чисто функциональным языком. Например, вы можете писать программы, которые изменяют данные, осуществляют обмен данными ввода-вывода, запускают потоки и вызывают исключения.Более того, система типов F # не требует строгого различия между выражениями, которые выполняют эти действия, и выражениями, которые не выполняют.

Ключевые слова

Полированный код Функциональное программирование Изменяемый локальный язык Построить текстовую строку

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

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

войдите в

, чтобы проверить доступ.

Предварительный просмотр

Невозможно отобразить предварительный просмотр. Скачать превью PDF.

Информация об авторских правах

© Дон Сайм, Адам Гранич и Антонио Чистернино 2010

Авторы и аффилированные лица

  • Share :

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

2023 © Все права защищены. Карта сайта