Pull to refresh

Comments 55

Вы ошиблись с точностью до наоборот.
Спасибо! Это правда, уже поправила

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

а можно в таком случае декларативный пример?
1) Яйца х2
2) Сковорода х1
3) Огонь х1
4) Option<Соль>
5) Функция готовки
6)…
7) Применить!
Это пример императивного интерпретатора декларативного языка. Каким образом будет получена не важно. Вы показываете пальцем и говорите: здесь должна быть яичница. Интерпретатор, допустим официант может заказать ее в другом ресторане, на кухне, сделать сам, собрать из атомов, разогреть вчерашнюю, главное, чтобы она соответствовала декларативному описанию.

яичница(яйца) = яйца |> чистка |> жарка

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

Таким языком может быть
SQL: SELECT item * 2 FROM arr
, но даже в этом случае мы определяем императивную операцию с умножением. В чисто декларативном подходе, мы должны сказать «здесь удвоенный список». Каким образом — не рассматривается в этой парадигме.
Пролог вроде изначально был полностью декларативный, нет?

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

Операции и отображения (функции) тоже можно описывать декларативно: вместо y = f(x) = 2 * x (пусть x: int) можно сказать, y — четное. Для любой g(x) функции можно можно сказать что её значения — «g'ные». Это позволяет до некоторой степени проворачивать фарш назад — вообще не определяя g, а описывая (декларативно) её свойства, получать ответы на вопросы (путем проверки, выполняется ли свойство для компонент агрегата). Приблизительно так и работает Пролог (несмотря на то что там есть "+")).

И кстати класс — это пример декларации — он описывает множество объектов со свойствами.

Декларативный подход, как таковой, существует. Это аксиоматика, денотационная семантика, лежащая в основе языка, даже императивного, наконец, просто способ декомпозиции и композиции задачи. Чаще всего, он используется в комплексе с императивными конструкциями, но иногда и сам по себе: HTML, CSS и SVG тому примеры.

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

Сковорода: умеет жарить, если горячая. Вмещается 1-4 яйца.
Огонь: умеет нагревать, если включен.
Мраморная плита: умеет жарить, если горячая. Вмещается 1-2 яйца.
Процессор без кулера. Умеет жарить. Вмещается 1 яйцо.
Попробую в виде программы:

Мне надо: Яичница, из яиц, жареных, две штуки, с солью.

Яйца пожареные, соленые.
Яйца сырые: если пожарить, будут пожаренные.
Яйца пожаренные: если добавить соль, будут соленые.
Соль: если добавить к чему-то, это что то станет соленым.
Яблоко. Если пожарить — будет пожареное.
Сковорода: умеет жарить, если горячая. Вмещается 1-4 яйца.
Огонь: умеет нагревать, если включен.
Мраморная плита: умеет жарить, если горячая. Вмещается 1-2 яйца.
Процессор без кулера. Умеет жарить. Вмещается 1 яйцо.

Прикол в том, что все строки я могу поменять местами.
А ещё могу написать: мне надо соленый жареный процессор.
Или Соленые сырые яйца
Или пожареные несоленые яйца (сковороды нет).
Или пожареные яблоки

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

Ага, или в ООП стиле на C++:
auto omelette = 
Fried { 
  MixOf {
    Two { Egg { } },
    One { SpoonOf { Salt{ } } } },
  OnPan { HeatedTo { OneHundred { Degrees { } } } },
  For{ Ten { Minutes { } } }
};

Как-то давно на Хабре в комментариях разгорелась длинная дискуссия о декларативном программировании с подобными примерами. Никак не могу найти тот пост.

… мне, конечно, очень интересно, где же в этом примере ООП.

Да тут все сущности являются объектами. Есть мнение, что хорошее ООП должно быть преимущественно декларативно.

Как отличить, являются эти сущности объектами или просто древовидной структурой данных?


Иными словами, я могу с минимальными синтаксическими изменениями переписать это на функциональный язык, и получить все то же самое, разве нет?

В отличие от структуры данных объекты имеют чётко определённое поведение. В данном примере у омлета может быть метод omelette.taste(). Просто они организованы в дерево с помощью композиции.

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

Но у вас в коде его нет.


В данном примере у омлета может быть метод omelette.taste()

Как только вы его вызовете, код разве не станет императивным?

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

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

На более высоком уровне может быть
auto breakfast = 
Table {
  With { omelette, tea, salad },
  OnIt { }
};

а на более низком уже более императивный код.

Так вот, пойнт в том, что на этом "более высоком уровне" ООП (в его нормальном понимании) — нет.

Это зависит от того, что понимать под ООП :) Чёткого определения не может дать даже Алан Кей. В последнее время появляется мнение, что правильное ООП ближе к функциональному и декларативному стилю, чем к ООП в традиционном его понимании.

Вопрос, однако, состоит в том, что же такое "правильное ООП" и где вы берете его определение.


(с Кеевским определением все понятно, под него этот код не попадает)

Это у вас свободная монада получилась. Поздравляю!

Получается Gherkin — ярчайший пример декларативного программирования?

Scenario: Some determinable business situation
     Given some precondition
       And some other precondition
    When some action by the actor
      And some other action
      And yet another action
    Then some testable outcome is achieved
     And something else we can check happens too
приготовленная яичница из n яиц :- разбитые на горячую сковородку яйца в количестве n штук и выдержанные в таком состоянии до отвердения белка.
горячая сковородка :- сковородка, поставленная на огонь 4 минуты назад.
разбитое яйцо :- содержимое яйца отделенное от скорлупы


Вы действительно не перепутали заголовки?

Декларативный описывает «что?» — «готовая яичница», и если он чисто декларативный, то не содержит совершенно никакой информации как ее сделать. Пример HTML, XML.

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

А последний пример, это функциональный стиль.

Императивный подход — КАК добиться нужного результата. Например: button.setBackgroundColor(RED) (есть эта строчка кода, которая выполняется до каких-то других и после каких-то других; эта строчка — это команда что-то сделать — "установить цвет фона")


Декларативный подход — ЧТО собой представляет нужный результат. Например: <button backgroundColor="red">... (это не команда — мы не говорим "во-первых я хочу кнопку, а во-вторых — давайте ей установим красный цвет фона"; вместо этого мы описываем результат — кнопка с красным фоном)


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

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

Звучит-то красиво, но попробуйте-ка перенести кусок HTML (он же декларативный) из одного веб-документа в другой.

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

Считаете — модульность и объектность при программировании пора включать в олимпиадное программирование?

За это мы, махровые декларативщики, и боремся! Практически идеальны в этом отношении конкатенативные языки, такие как Joy или J.

Получится "Шахбокс" или "офицерское многоборье" для программистов — в первом раунде решаешь с выводом математический алгоритм (в т. ч. декларативно) и демонстрируешь вывод в LaTexe.
Во втором — разрабатываешь модульно-объектную структуру программы.
В третьем — набираешь и правишь стиль и успешно компилируешь.
В четвертом — показываешь навыки оптимизации с измерением быстродействия.
Всё, все стадии — на время и на очки.
И тогда мнения — "программист-олимпиадник — это феееее!" — не будет.

Декларативно яичница выглядит вот так: «яичница»

Ну, я бы так:
яичница.жареная = true;

ну и дальше уже, по фантазии :)
public bool жареная { get { return _жареная;}; set { пожаритьЯичницу(value);}

Это как раз императивный код.

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

Во-первых, нет: "ниже уровнем" HTML ничего нет — HTML просто чем-то интерпретируется.


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

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


Имеративно:


div = docoment.getElementById("#someid");
for(var i=0; i<=10; i++)
div.appendChild(document.createElement("span"));


Декларвтивно (псевдокод):


<div id="someid">
<for var="i" start="0" end="10">
<span><span>
</for>
</div>


Хорошим примером декларативных подходов являются HTML, XML+XSLT. Различные файлы конфигураций (package.json etc) тоже в своем роде декларативных программы. Jasonette — декларативных фреймворк.
Отличным примером декларативного подхода в императивных языках являются аннотации (декораторы):
Имеративно:


class MyAnalyser extends Analyse {

}

Object.seal(MyAnalyser.constructor);
Object.seal(MyAnalyser.constructor.prototype);


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


@Sealed
class MyAnalyser extends Analyser {

}

соглашусь, что может и не очень правильно с точки зрения кого-то научить (тк сама запуталась), но после пары-тройки комментариев мне кажется, что получилось все же разобраться :)

Пока единственный пример декларативного описания яичницы дал @Unrull. В нём хорошо разделены описание и интерпретация.


Декларативное описание состоит из неупорядоченной последовательности определений, позволяющей однозначно редуцировать выражение, определяющее конкретную яичницу к нормальной форме. Саму яичницу будет делать исполнитель, он получит императивный объектный код, в который транслируется нормальная форма, определяющая яичницу. В решении @Unrull дана нормальная форма в виде свободной монады. Её соответствующей F-алгеброй можно интерпретировать в последовательность действий, в том числе, побочных.


Гораздо, впрочем, лучше разницу между декларативным и императивным подходами показывает пример с описанием изображения, скажем, домика:


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


house = (roof `above` (window `over` walls)) `at` (0,0) 
roof = triangle 100 50 `color` "blue"
walls = square 100 `color` "brown"
window = w' `above` w'
  where w = square 10
         w' = w `beside` w

Эту программу пишет и отлаживает человек. Всю вычислительную работу выполняют конструкторы примитивов square и triangle, а также универсальные комбинаторы: above, below, over и at.


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


function DrawHouse () {
  // roof
  newPath()
  moveTo(0,100)
  lineTo(100,100)
  lineTo(50,150)
  lineTo(0,100)
  setColor("blue")
  stroke()

  // walls
  newPath()
  moveTo(0,0)
  lineTo(100,0)
  lineTo(100,100)
  lineTo(0,100)
  lineTo(0,0)
  setColor("brown")
  stroke()
  ...
}

Не удержусь, приведу пример функционального декларативного описания на Haskell.


Начнём с описания омлета:


omelette :: Food f => Int -> f
omelette n = fried . scrambled . map broken $ eggs
  where
    eggs = take n $ repeat Egg
    broken Egg = Scrambled Yolk <> Scrambled EggWhite
    scrambled = getScrambled . fold

В этом описании используются стандартные функции для создания и обработки коллекций: repeat, take и foldMap, универсальная функция: fried, полугруппа Scrambled ну, и, собственно, яйца.


Пусть для яйца и его частей будут определены атомарные типы:


data Yolk = Yolk
data EggWhite = EggWhite
data EggShell = EggShell
data Egg = Egg

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


Наконец, опишем универсальный процесс жарки:


fried :: Food f => f -> f
fried x = heated 180 x `for` Minutes 8

Здесь используются универсальные функции из гипотетической библиотеки Reactive.Bananas.Cooking с такими сигнатурами:


heated :: Temperature -> a -> Process a
for :: Process a -> Time -> a

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

Насчёт второго примера в статье. Если уж говорить совсем декларативно, то мы хотим получить что-то вроде
return SequenceFrom { array, WithEachValue { Two { Times { } }, TheOriginal { } } };
    auto s1 =
        IntSequenceFrom(
            arr,
            WithEachValueBe(
                Doubled()));

Пример на С++
#include "stdafx.h"
#include <vector>
#include <iostream>

using namespace std;

int main()
{
    auto IntSequenceFrom = [&](auto seq, auto sel) {
            return [=]() {
                    vector<int> res(seq.size());
                    for (size_t i = 0; i < seq.size(); ++i) sel(res, seq, i);
                    return res;
                };
        };
    auto WithEachValueBe = [&](auto f) {
            return [=](auto& res, auto seq, size_t i) { res[i] = f(seq[i]); };
        };
    auto WithEvenValuesBe = [&](auto f) {
            return [=](auto& res, auto seq, size_t i) { if (i % 2 == 0) res[i] = f(seq[i]); };
        };
    auto WithOddValuesBe = [&](auto f) {
            return [=](auto& res, auto seq, size_t i) { if (i % 2 != 0) res[i] = f(seq[i]); };
        };
    auto Both = [&](auto f1, auto f2) {
            return [=](auto& res, auto seq, size_t i) { f1(res, seq, i) , f2(res, seq, i); };
        };
    auto TwoTimes = [&](auto f) {
            return [=](auto val) { return 2 * f(val); };
        };
    auto TheProductOf = [&](auto f1, auto f2) {
            return [=](auto val) { return f1(val) * f2(val); };
        };
    auto TheFirstElement = [&]() {
            return [=](auto val) { return val.first; };
        };
    auto TheSecondElement = [&]() {
            return [=](auto val) { return val.second; };
        };
    auto Doubled = [&]() {
            return [=](auto val) { return val * 2; };
        };

    vector<int> arr{1,2,3};
    auto s1 =
        IntSequenceFrom(
            arr,
            WithEachValueBe(
                Doubled()));
    for (auto v : s1()) cout << v << " ";
    cout << endl;

    vector<pair<int, int>> pairs = {{2,11}, {3,22}, {4,33}};
    auto s2 =
        IntSequenceFrom(
            pairs,
            WithEachValueBe(
                TheProductOf(
                    TheFirstElement(),
                    TheSecondElement())));
    for (auto v : s2()) cout << v << " ";
    cout << endl;

    auto s3 =
        IntSequenceFrom(
            pairs,
            Both(
                WithEvenValuesBe(
                    TwoTimes(
                        TheProductOf(
                            TheSecondElement(),
                            TheFirstElement()))),
                WithOddValuesBe(
                    TwoTimes(
                        TheFirstElement()))));
    for (auto v : s3()) cout << v << " ";
    cout << endl;
    return 0;
}

Видите ли какая штука. Инструкция "как приготовить яичницу" сама по себе императивна.

… в отличие от описания "яичница — это..."

Подкину уголька..


Императивный функциональный код:


яичница = ()=> последовательность(
    ()=> яйцо ,
    яйцо => разбей( яйцо ) ,
    разбитое_яйцо => убери_скорлупу( разбитое_яйцо ),
    яйцо_без_скорлупы => пожарь( сковорода )( яйцо_без_скорлупы ),
    жаренное_яйцо => добавь_приправы( жаренное_яйцо )
)

Или то же самое:


яичница = ()=> последовательность( ()=> яйцо , разбей, убери_скорлупу, пожарь( сковорода ), добавь_приправы )

Или то же самое:


яичница = ()=> добавь_приправы( пожарь( сковорода )( убери_скорлупу( разбей( яйцо ) ) ) )

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


класс Процесс_готовки_яичницы {
    получить сковорода() { вернуть новое Яйцо }
    получить яйцо() { вернуть новое Яйцо }
    получить разбитое_яйцо() { вернуть это.яйцо.разбить() }
    получить яйцо_без_скорлупы() { вернуть это.разбитое_яйцо.убрать_скорлупу() }
    получить жаренное_яйцо() { вернуть это.сковорода.пожарь( это.яйцо_без_скорлупы ) }
    получить яичница() { вернуть это.жаренное_яйцо.добавь_приправы() }
}

Или то же самое:


класс Процесс_готовки_яичницы {
    получить яичница() { вернуть это.жаренное_яйцо.добавь_приправы() }
    получить жаренное_яйцо() { вернуть это.сковорода.пожарь( это.яйцо_без_скорлупы ) }
    получить сковорода() { вернуть новое Яйцо }
    получить яйцо_без_скорлупы() { вернуть это.разбитое_яйцо.убрать_скорлупу() }
    получить разбитое_яйцо() { вернуть это.яйцо.разбить() }
    получить яйцо() { вернуть новое Яйцо }
}
Пример декларативного — SQL :) Делаете вы выборку по таблице, и один и тот же запрос может отрабатываться разными способами. И только explain plan вам поможем понять, чем же СУБД в одном случае занята 5 минут, а в другом «полсекунды». Иногда в код запроса ставишь уже оптимизатору хинты, чтобы дурью не маялся на основе собранной статистики. Иногда хочется немного императивности в SQL.
Декларативное программирование — это набор верхнеуровневых инструкций, детали реализации которых скрыты за исполнителем этих инструкций.
Императивное программирование позволяет описывать инструкции с использованием «низкоуровневых» (в рамках ЯП) выражений.
При этом, если подумать, любое выражение — в действтиельности задекларированная ЯП инструкция. Я бы это, своевольно, назвал одним из доказательств того что программа — это конечный автомат.
Декларативное программирование — это набор верхнеуровневых инструкций, детали реализации которых скрыты за исполнителем этих инструкций.
Императивное программирование позволяет описывать инструкции с использованием «низкоуровневых» (в рамках ЯП) выражений.

Это, всё же, вопрос не парадигмы, а уровня абстракции. На ФЯП можно написать на чистых лямбдах или SKI комбинаторах весьма низкоуровневый код, а императивный FORTH позволяет выйти на любой уровень абстракции, расширяя словарь.


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

Программа, это инструкция для автомата, а не сам автомат. Но вы недалеки от истины с точки зрения вычислителя: правда не конечный автомат, а автомат с магазинами, или счётчиками, эквивалентен машине Тьюринга, а ЯП для написания программ для него — полон по Тюрингу. А именно с полными ЯП мы, обычно, и работаем.

Программа, это инструкция для автомата, а не сам автомат

Пользователь — исполнитель программы, интерфейс — набор инструкций программы, программа — КА

На правах попытки разобраться в сказанном (статье + комментариях к ней). Тоже на днях встретился с вопросом понимания и соотнесения императивного и декларативного программирований.


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


Основа процесса мышления — это выявление разнокачественностей, т.е. способность всё разделить на части (простейшая из которых пара из это и все_остальное_не_это).


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


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


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


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


  • Яичница состоит из яиц, соли, масла, при этом хорошая яичница — тёплая.
  • Яйца в яичнице жаренные — зачастую по нраву потребителя.

const requiredScrambledEggs = { egg: 2, salt: 5, oil: 0.5, temperature: 35, roast: 'low' };

и да, должен быть кто-то/что-то способное её предоставить по требованию.


Выходит, что результатом декларативного программирование есть множество описаний чего-то (HTML+CSS — как должна выглядеть страница и что содержать, SVG — какие геометрические фигуры где и с какими параметрами отражать).


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


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


При этом в декларативном программировании мы не задумываемся о том как будет получен результат (т.е. какие действия и на каком исполнители будут выполнены) — главное у нас есть набор описательных примитивов (div, input, span либо rect, path, p) — и нам нужно разбить выражаемую/отражаемую информацию на части и перенести в код (если в рамках примитивов это вообще выразимо), указав какие части и в каких взаимосвязях есть.


Императивное программирования предполагает отражения 2-х вещей: последовательности команд и параметров этих команд (что в сущности есть информация, часть из которой может быть введена декларативно, другая получена на ввод, третья — вычислена/преобразована из имеющейся). Тут мы так-же ограничены множеством возможных для выполнения команд исполнителя.
В js можно предположить, что у нас есть отражение робота повара в систему в виде встроенного объекта (cook), с методами отражающими известные ему команды. Для этого робота мы задаём последовательность действий типа найди сковородку, включи плиту, поставь сковородку на плиту, найди и налей масла… и т.д.


function getReadyScrambledEggs(meal){
    const fryingPan = cook.findFryingPan();
    cook.setOnFire(fryingPan);

    while(fryingPan.getTemperature() < 50) 
        cook.wait();
    // тут 50 - константа, т.е. некая фиксированная информация, задекларированная в условии цикла

    const eggs = cook.findEggs(meal.egg); // из requiredScrambledEggs
    ...
}

Выходит:


  1. декларативное программирование в общем случае возможно без императивного (исполнителем может быть и человек, способности которого — его данность);
  2. императивное без деклараций (пускай и в скрытом виде) сложно себе представить (только если все данные неким образом вводятся извне, а код только их преобразование описывает);
  3. говоря о декларативном программировании ожидают отражение в код информации (которая потом будет построена либо по которой будет что-то построено — описание цели);
  4. говоря о императивном программировании ожидают создание управляющей программы которая будет давать набор команд исполнителю чего делать что-бы получить требуемый результат (в первом приближении сам набор команд записанный в должной последовательности — поскольку в общем случае возможны разные стартовые ситуации, есть условия/ветвления, то я уточнил — создание управляющей программы, которая выдаст должную для данной ситуации последовательность команд).

У вас оба примера это императивный стиль.

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

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

В декларативном виде все тоже самое будет выглядеть так:

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

Императив это команда в виде повелительного глагола. Любая команда это императив.
Декларация это констатация факта.

Императив: Все на стачку!
Декларатив: Все на стачке!

Императив: Сюда иди!
Декларатив: Тут стоишь.

Sign up to leave a comment.

Articles