императивность vs декларативность
Jul. 22nd, 2007 11:24 amВ программировании существует два принципиальных подхода, на которых строятся бесчисленные техники: императивный подход и декларативный подход.
При чисто-императивном подходе программа, которую нужно исполнить, полностью содержит в себе граф переходов по самой себе. Можно сказать, что для императивной программы не существует внешних по отношению к ней событий, она является цельной такой заизолированной вещью в себе.
При чисто-декларативном подходе, наоборот, программы как цельного куска кода не существует, а вместо неё существует множество коротеньких правил или формул, определяющих, как реагировать на то или иное событие.
Изначально сам наличный язык определял подход программирования (императивный: машинный код, Фортран, Бейсик, Алгол, Паскаль; декларативный: Лисп, Пролог), но постепенно выразительная мощность языков повышалась, а в массах одновременно росло осознание необходимости смешивать подходы в определённых пределах, поэтому современная программа на Си++, Яве или Перле имеет признаки как того, так и другого. Например, возникновение оконных интерфейсов сразу и с необходимостью потребовало, чтобы программа была способна реагировать на интерфейсные события: время, посвящённое чисто себе, стало непозволительной роскошью.
Теперь ближе к жизни. Когда мы говорим, что "в геноме записана программа жизни организма", имеется в виду декларативная программа. Отдельным декларациям соответствуют записи отдельных генов с их промотерами, терминаторами и прочими органами условного выполнения. Однако, выполнение её не чисто декларативно.
Дело в том, что декларативный подход вообще весьма пассивный, "иньский" - полное согласие со средой и никакого проявления личной воли. Как можно проявлять личную волю, когда тебя постоянно дёргает среда? Значит, нужно выстроить некоторый барьер, заизолироваться от среды, и только там, в своей песочнице, проявлять эту самую волю, самость. И организмы, каждый по-своему, пытаются строить барьеры и самовольничать.
Прокариоты (безъядерные одноклеточные) практически не имеют материальных мощностей для разделения событий в пространстве, поэтому они пытаются разделять временнОй ресурс. Их инструмент - это такой способ структурирования генома, где материал для реакций, которые должны происходить последовательно, закодирован последовательно в т.н. "опероны" - многогенные участки с одной общей точкой входа. Внешнее событие вызывает транскрипцию-трансляцию оперона (у прокариотов, поскольку ядра нет, эти процессы можно считать слитыми в один), а дальше управление переходит к собственно биохимии оперона, во время исполнения которого прокариот обладает "самостью", "личной волей". Поэтому прокариот должен быть предельно эффективным, ведь пока он выражает свою самость, он глух к внешним сигналам и его могут попросту сожрать. (Может быть поэтому у них такие короткие геномы и нет интронов?)
Эвкариоты (ядерные и большей частью многоклеточные) ставят как раз не на время, а на пространство. Их декларативные программы короче, каждая - длинной в один ген, но вот количество контекстов, где эти программы запускать, огромно. Во-первых, чётко разделены пространства ядра и цитоплазмы, потом в клетке есть дополнительные органеллы (заизолированные для проведения специфических реакций), но главное - ввиду многоклеточности над клеткой существует целый новый "этаж", где происходит в основном обработка внутренних, а не внешних для организма сигналов.
Подводя итог можно сказать, что мера декларативности (прозрачности, пассивной реактивности) программы (как живой, так и неживой) соответствует её интерактивности со средой. Чем больше интерфейса, тем больше декларативности, а чем больше самости и личной воли - тем больше императивности.
Можно ещё наблюсти интереснейшую параллель между оседлыми и кочевыми народами по Генону (см. напр. "Царство количества и знамения времени"), разница между которыми также в том, что одни живут во времени, а другие - в пространстве. Так можно понять, кто в живой природе соответствует евреям и цыганам, а кто - китайцам, но это отдельная большая тема :)
При чисто-императивном подходе программа, которую нужно исполнить, полностью содержит в себе граф переходов по самой себе. Можно сказать, что для императивной программы не существует внешних по отношению к ней событий, она является цельной такой заизолированной вещью в себе.
При чисто-декларативном подходе, наоборот, программы как цельного куска кода не существует, а вместо неё существует множество коротеньких правил или формул, определяющих, как реагировать на то или иное событие.
Изначально сам наличный язык определял подход программирования (императивный: машинный код, Фортран, Бейсик, Алгол, Паскаль; декларативный: Лисп, Пролог), но постепенно выразительная мощность языков повышалась, а в массах одновременно росло осознание необходимости смешивать подходы в определённых пределах, поэтому современная программа на Си++, Яве или Перле имеет признаки как того, так и другого. Например, возникновение оконных интерфейсов сразу и с необходимостью потребовало, чтобы программа была способна реагировать на интерфейсные события: время, посвящённое чисто себе, стало непозволительной роскошью.
Теперь ближе к жизни. Когда мы говорим, что "в геноме записана программа жизни организма", имеется в виду декларативная программа. Отдельным декларациям соответствуют записи отдельных генов с их промотерами, терминаторами и прочими органами условного выполнения. Однако, выполнение её не чисто декларативно.
Дело в том, что декларативный подход вообще весьма пассивный, "иньский" - полное согласие со средой и никакого проявления личной воли. Как можно проявлять личную волю, когда тебя постоянно дёргает среда? Значит, нужно выстроить некоторый барьер, заизолироваться от среды, и только там, в своей песочнице, проявлять эту самую волю, самость. И организмы, каждый по-своему, пытаются строить барьеры и самовольничать.
Прокариоты (безъядерные одноклеточные) практически не имеют материальных мощностей для разделения событий в пространстве, поэтому они пытаются разделять временнОй ресурс. Их инструмент - это такой способ структурирования генома, где материал для реакций, которые должны происходить последовательно, закодирован последовательно в т.н. "опероны" - многогенные участки с одной общей точкой входа. Внешнее событие вызывает транскрипцию-трансляцию оперона (у прокариотов, поскольку ядра нет, эти процессы можно считать слитыми в один), а дальше управление переходит к собственно биохимии оперона, во время исполнения которого прокариот обладает "самостью", "личной волей". Поэтому прокариот должен быть предельно эффективным, ведь пока он выражает свою самость, он глух к внешним сигналам и его могут попросту сожрать. (Может быть поэтому у них такие короткие геномы и нет интронов?)
Эвкариоты (ядерные и большей частью многоклеточные) ставят как раз не на время, а на пространство. Их декларативные программы короче, каждая - длинной в один ген, но вот количество контекстов, где эти программы запускать, огромно. Во-первых, чётко разделены пространства ядра и цитоплазмы, потом в клетке есть дополнительные органеллы (заизолированные для проведения специфических реакций), но главное - ввиду многоклеточности над клеткой существует целый новый "этаж", где происходит в основном обработка внутренних, а не внешних для организма сигналов.
Подводя итог можно сказать, что мера декларативности (прозрачности, пассивной реактивности) программы (как живой, так и неживой) соответствует её интерактивности со средой. Чем больше интерфейса, тем больше декларативности, а чем больше самости и личной воли - тем больше императивности.
Можно ещё наблюсти интереснейшую параллель между оседлыми и кочевыми народами по Генону (см. напр. "Царство количества и знамения времени"), разница между которыми также в том, что одни живут во времени, а другие - в пространстве. Так можно понять, кто в живой природе соответствует евреям и цыганам, а кто - китайцам, но это отдельная большая тема :)
no subject
Date: 2007-07-22 09:45 pm (UTC)no subject
Date: 2007-07-22 11:20 pm (UTC)no subject
Date: 2007-07-23 09:41 am (UTC)Тут, конечно, смотря что писать, но в общем, функциональная программа стремится инкапсулировать весь необходимый контекст, и до окончания вычисления никуда не обращаться. Другое дело что такие куски бывают небольшими и подвешены на события - но это уже вопрос организации программы в целом.
В общем получается что декларативность/императивность и интерактивность/неинтерактивность вполне ортогональны.
no subject
Date: 2007-07-23 01:05 pm (UTC)Если взять например рекурсивную функцию, вычисляющей факториал, вызов "факториал(6)" ничего не знает о собственной предыстории. Был ли он вызван средой, или являлся частью более глубокой рекурсии для вычисления факториала(10) ? Узнать это нет никакой возможности.
Если вернуться к нашей ассоциации с жизню, то время у соответствующего контексту исполнения субъекта не течёт. Значения параметров не меняются (т.е. время даже измерить нечем). Внешний стимул (=вызов) порождает реакцию (возвращаемое значение), и максимум за такую жизнь удаётся принять один-единственный выбор (уходить в рекурсию или нет).
no subject
Date: 2007-07-23 01:44 pm (UTC)Я неправильно понял слово "интерактивность" в начальном контексте.
(А ответ относился к поведению программы после вызова)
no subject
Date: 2007-07-23 01:46 pm (UTC)switch (c)
{
case 'I': myDna.Add(Base.I); break;
case 'C': myDna.Add(Base.C); break;
case 'F': myDna.Add(Base.F); break;
case 'P': myDna.Add(Base.P); break;
}
Декларативно:
Dictionary
switch (c)
{
case 'I': myDna.Add(Base.I); break;
case 'C': myDna.Add(Base.C); break;
case 'F': myDna.Add(Base.F); break;
case 'P': myDna.Add(Base.P); break;
}
Декларативно:
Dictionary<char, Pattern> c2p = new Dictionary<char, Pattern>();
c2p.Add('I', Pattern.I);
c2p.Add('C', Pattern.C);
c2p.Add('F', Pattern.F);
c2p.Add('P', Pattern.P);
... и где-то в конце опять условно-императивно es.Add(c2p[c]);
Разница вовсе не в объёме взаимодействия с окружающей средой. В конце концов и та, и другая программы исполняются на одном и том же фон-неймановском компе и даже написаны на одном и том же языке. Разница в другом: в том, что одна программа описывает последовательность действий, а другая -- результат.
no subject
Date: 2007-07-23 02:02 pm (UTC)no subject
Date: 2007-07-23 03:29 pm (UTC)Чем занимаются данные куски кода (на самом деле они занимаются разными вещами, но довольно похожими по сути): нужно превратить введённый снаружи символ А в один из символов Б. Императивный подход -- это когда программист в явном виде пишет, что, дескать, есть у нас символ А, пройдёмся по всем возможным вариантам А1 .. Ан и в каждом из них выведем соответствующий символ Б_и. А есть императивный подход, когда программист говорит, что символу А1 соответствует символ Б1 и так далее. В первом случае действие производится, во втором действие только подразумевается, и то со стороны, так-то у нас есть прекрасная табличка, которую только сильно извращённые умы могут воспринять как руководство к действию, а не как некую догму, которую можно сочетать с другими догмами чтобы получать новые догмы.
no subject
Date: 2007-07-23 03:56 pm (UTC)Интересный пример. Получается, что "верх императивности" - это вообще даже не использовать никаких структур данных, вернее выразить любые нетривиальные данные (в данном примере - таблицу перевода) через граф перехода по коду.
"Верх декларативности" - наоборот, убрать весь код, оставить одну хеш-таблицу, а управление передать некоторой интерпретирующей среде. Настоящая декларативная программа (например, на Прологе) по сути и есть база данных, над которой по своим (императивным) правилам копается специальный интерпретатор.
Такой императивный интерпретатор - как раз средство притянуть за уши эту базу к фон-Неймановской архитертуре. Иначе в системе нет действующего лица - она пассивная, как пробирка с ДНК мамонта.