Стратегия вычисления

Поделись знанием:
Перейти к: навигация, поиск

Стратегия вычисления (англ. evaluation strategy) — правила семантики языка программирования, определяющие, когда следует вычислять аргументы функции (метода, операции, отношения), и какие значения следует передавать. Например, стратегия «вызов-при-упоминании/передача-по-ссылке» (call-by-worth/pass-by-reference) диктует, что аргументы должны быть вычислены перед выполнением тела вызываемой функции, и что ей должны быть предоставлены две возможности в отношении каждого аргумента: чтение текущего значения и его изменение посредством операции присваивания[1]. На эту стратегию похожа стратегия редукции[en] в лямбда-исчислении, но есть отличия.

На практике, модель вычисления многих промышленных языков (Java, C#) сводится к стратегии «вызов-при-упоминании/передача-по-ссылке». Некоторые более старые языки, в особенности небезопасные, такие как C++, сочетают несколько разных моделей вызова. Исторически «вызов по значению» и «вызов по имени» восходят к Алголу-60, созданному в конце 1950-х годов. Только чистые функциональные языки, такие как Clean и Haskell, используют «вызов по необходимости».

Примечание — в русскоязычной литературе стратегия вычислений также называется «способом передачи параметров», «моделью вычислений» или «моделью вызова». Последний вариант может вызвать путаницу с соглашением о вызове (calling convention). Термин «передача параметров» для многих стратегий вычисления является некорректным.





Строгие вычисления

Строгая модель вычислений (англ. strict evaluation) означает, что аргументы всегда вычисляются полностью до применения функции к ним.

В нотации Чёрча[en], энергичные вычисления (eager evaluation) операторов соответствуют строгим вычислениям для функций, и по этой причине строгие вычисления временами называются «энергичными». Большинство существующих языков используют строгие вычисления для функций.

Аппликативный порядок

Аппликативный порядок вычислений (англ. applicative order), также «вычисления слева направо, изнутри наружу», (leftmost innermost)[2][3], означает стратегию вычислений, при которой обход снизу вверх по AST вычисляет аргументы слева направо в редуцируемых выражениях.

В отличие от вызова по значению, аппликативный порядок вычислений максимально редуцирует термы в теле функции до её применения.

Вызов по значению (call-by-value)

Вызов по значению (англ. call-by-value) является наиболее широко распространённой стратегией вычислений, её можно видеть в самых разных языках, от Си до Scheme. При вызове по значению, выражение-аргумент вычисляется, и полученное значение связывается[en] с соответствующим формальным параметром функции (обычно посредством копирования этого значения в новую область памяти). При этом, если язык разрешает функциям присваивать значения своим параметрам, то изменения будут касаться лишь этих локальных копий, но видимые в месте вызова функции значения останутся неизменными по возвращении.

На самом деле, вызов по значению представляет собой не одну конкретную модель вызова, а семейство моделей, в которых аргументы вычисляются до передачи телу функции. Большинство языков (Common Lisp, Eiffel, Java), использующие вызов по значению, вычисляют аргументы функций слева направо, но некоторые вычисляют их справа налево, а некоторые (Scheme, OCaml, Си) не определяют порядок вычисления.

Скрытые ограничения

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

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

Объяснение, что язык «передаёт параметры по значению, где значением является ссылка», встречается весьма часто (но его не следует отождествлять с вызовом по ссылке); иначе это называется вызовом по соиспользованию. Из-за этого вызов по значению в языках Java и Visual Basic ведёт себя существенно иначе, нежели вызов по значению в языках Си и Pascal. В Си или Паскале при передаче массивной структуры данных в функцию вся структура будет скопирована (если только аргумент не является в действительности ссылкой на структуру данных), что потенциально существенно снизит быстродействие; при этом изменения состояния структуры не будут видны в вызывающем контексте. В Java и Visual Basic копируется всегда лишь ссылка на структуру, что выполняется быстро, и изменение структуры будет видно в месте вызова.

Вызов по ссылке (call-by-reference)

При вызове-по-ссылке (англ. call-by-reference), или передаче-по-ссылке (pass-by-reference), функция неявно получает ссылку на переменную, использованную в качестве аргумента, вместо копии её значения.

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

Многие языки поддерживают вызов по ссылке в той или иной форме, но лишь немногие используют его по умолчанию — например Perl. Ряд языков, например, C++, PHP, Visual Basic .NET, C# и REALbasic, по умолчанию используют вызов по значению, но предоставляют специальный синтаксис для вызова по ссылке. C++ дополнительно представляет уникальную стратегию «вызов-по-ссылке-на-константу».

Системы типов некоторых языков, использующих вызов по значению и непосредственно не поддерживающих вызов по ссылке, предоставляют возможность явно определять ссылки (объекты, ссылающиеся на другие объекты), в частности, указатели (объекты, представляющие собой адреса других объектов в памяти ЭВМ). Их использование позволяет симулировать вызов по ссылке внутри семантики вызова по значению. Такое решение применяется, например, в языках Си и ML. Оно не является самостоятельной стратегией вычисления — язык по-прежнему вызывает по значению — но иногда его называют «вызовом-по-адресу» (call-by-address) или «передачей-по-адресу» (pass-by-address). В небезопасных языках, например в Си или C++, оно может приводить к ошибкам доступа к памяти, таким как разыменование нулевого указателя, соответственно, к затруднению понимания программы и первоначального изучения языка. В ML ссылки безопасны по типам и по доступу к памяти.

Близкий эффект также обеспечивает стратегия «вызов по соиспользованию», применяемая в таких языках как Java, Python, Ruby.

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

Следующий пример демонстрирует симуляцию вызова по ссылке в языке E:

 def modify( var p, &q )
 {
     p := 27   # параметр передан по значению - только локальное значение изменяется
     q := 27   # параметр передан по ссылке - изменяется переменная, использованная при вызове
 }

 ? var a := 1
 # значение: 1
 ? var b := 2
 # значение: 2
 ? modify( a, &b )
 ? a
 # значение: 1
 ? b
 # значение: 27

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

void Modify( int p, int * q, int * o ) 
{
    // все параметры переданы по значению
    p = 27;   // изменяется только локальное значение
    *q = 27;  // изменяется внешняя переменная, на которую указывает q
    *o = 27;  // изменяется внешняя переменная, на которую указывает o
}
int main()
{
    int a = 1;
    int b = 1;
    int x = 1;
    int * c = &x;
    Modify( a, &b, c );  // 1-й параметр - значение переменной a
                         // 2-й параметр - адрес переменной b
                         // 3-й параметр - значение переменной c, являющееся адресом переменной x
        // b и x изменяются
    return(0);
}

Вызов по соиспользованию (call by sharing)

Вызов-по-соиспользованию или вызов-с-разделением-ресурсов (англ. call-by-sharing), также вызов-по-объекту (call-by-object), также вызов-по-соиспользованию-объекта или вызов-с-разделяемым-объектом (call-by-object-sharing), подразумевает, что значения в языке основаны на объектах, а не на примитивных типах, то есть «обернуты» («упакованы», англ. boxed). При вызове по соиспользованию функция получает копию ссылки на объект. Сам объект не копируется — он оказывается соиспользуемым или разделяемым. Как следствие, присваивание аргументу в теле функции не имеет эффекта в вызывающем её контексте, но присваивание компонентам этого аргумента — имеет.

Вызов по соиспользованию впервые реализован в языке CLU в 1974 году под руководством Барбары Лисков и других[4].

Эта стратегия используется в языках Python[5], Iota[en][6], Java (для ссылок на объекты), Ruby, JavaScript, Scheme, Ocaml, AppleScript, и многих других. Однако, терминология в сообществах разных языков различается. Например, в сообществе Python используется термин «вызов по соиспользованию»; в сообществах Java и Visual Basic ту же семантику часто описывают как «вызов по значению, где „значением“ является ссылка на объект»; в сообществе Ruby говорят, что Ruby «использует вызов по ссылке» — несмотря на то, что семантика вызова в этих языках идентична.

Для неизменяемых объектов нет разницы между вызовом-по-соиспользованию и вызовом-по-значению, за исключением идентичности этих объектов. Применение вызова по соиспользованию является альтернативой входных/выходных параметров[7] — изменение параметра здесь не означает присваивание параметру; параметр не перезаписывается, а изменяет состояние, сохраняя свою идентичность.

Например, в языке Python списки являются изменяемыми объектами, поэтому:

def f(l):
    l.append(1)
m = []
f(m)
print m

— напечатает «[1]», так как аргумент «l» был изменён.

Разницу между изменением и присваиванием демонстрирует следующий пример. Такой код:

def f(l):
    l += [1]
m = []
f(m)
print m

— напечатает «[1]», так как оператор «l += [1]» ведёт себя как «l.extend([1])»; но похожий код:

def f(l):
    l = l + [1]
m = []
f(m)
print m

— напечатает"[]", так как оператор «l = l + [1]» создаёт новую локальную переменную, вместо того, чтобы изменять аргумент[8].

Наглядно семантику обёрнутых (boxed) значений и вызова-по-соиспользованию демонстрирует поведение следующей программы:

x = [[]] * 4
x[0].append('a')
x[1].append('b')
x[2].append('c')
print(x)

>>[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]

Оператор «x = [[]] * 4» создаёт пустой список (назовём его «l»), а затем новый список (связываемый с идентификатором[en] «x») из четырёх элементов, каждый из которых является ссылкой на «l», то есть «x = [ l, l, l, l ]». Последующие обращения к разным элементам списка «x» изменяют объект «l». То же происходит и при печати списка «x»: поскольку он состоит из четырёх ссылок на «l», то и состав «l» распечатывается четыре раза.

Вызов по копированию — восстановлению (call by copy-restore)

Вызов-по-копированию-восстановлению (англ. call-by-copy-restore), также копируй-на-входе копируй-на-выходе (copy-in copy-out), также вызов-по-значению-в-результате (call-by-value-result) или вызов-по-значению-при-возврате (call-by-value-return), как его называют в сообществе языка Fortran, представляет собой особый случай вызова по ссылке, в котором предоставляемая ссылка является уникальной для вызывающего контекста. Этот вариант интересен в контексте многопроцессорных систем и удалённого вызова процедур: если параметром функции является ссылка, которая может быть доступна для другого исполняемого процесса, то её содержимое может быть скопировано в новую ссылку, которая уже будет недоступна; при возвращении из функции изменённое содержимое этой новой ссылки будет скопировано в исходную ссылку («восстановлено»).

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

Если ссылка передаётся неинициализированной, такая стратегия вычисления может называться вызов-по-результату (англ. call-by-result).

Частичные вычисления

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

Нестрогие вычисления

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

Нестрогое вычисление функций соответствует ленивому вычислению операторов в нотации Чёрча[en], и поэтому нестрогие вычисления часто называются «ленивыми».

В ряде языков (Си, C++ и др.) булевы выражения имеют нестрогий порядок вычисления, называемый в русской литературе «вычислениями по короткой схеме» (short-circuit evaluation), где вычисления прекращаются, как только результат становится однозначно предсказуем — например, значение «истина» в операции дизъюнкции, «ложь» в операции конъюнкции, и так далее. Операторы ветвления зачастую также имеют ленивую семантику вычислений, то есть возвращают результат всего оператора, как только однозначная ветвь его породит.

Нормальный порядок

Нормальным порядком вычислений (англ. Normal order; также «вычислениями слева направо, снаружи внутрь», leftmost outermost) называют стратегию вычислений, при которой охватывающее выражение полностью редуцируется, применяя функции до вычисления аргументов.

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

Вызов по имени (call-by-name)

В стратегии вызов-по-имени аргументы не вычисляются перед вызовом функции. Вместо этого они подставляются непосредственно в тело функции (используя подстановку, препятствующую захвату[en]), и далее вычисляются по месту требования. Если аргумент не используется в теле функции, он вообще не вычисляется; если он используется несколько раз, он повторно вычисляется при каждом вхождении (см. Трюк Йенсена).

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

Впервые вызов по имени был применён в языке Алгол-60. .NET-языки могут симулировать вызов по имени, используя делегаты или Expression<T>-параметры. В последнем случае функция получает AST. В языке Eiffel реализованы агенты, представляющие собой операции, выполняемые по требованию.

Вызов по необходимости (call-by-need)

Вызов-по-необходимости (англ. call-by-need) представляет собой мемоизированный вариант вызова по имени, где, если аргумент вычислен, его значение сохраняется для последующего использования. В случае «чистоты языка» (при отсутствии побочных эффектов) это производит тот же результат, что и вызов по имени; а в случаях, когда аргумент используется два и более раз, вызов по необходимости почти всегда работает быстрее.

Поскольку вычисляемые выражения могут иметь очень глубокую степень вложения, то языки, использующие вызов по необходимости обычно не поддерживают побочные эффекты (такие как изменение состояния) напрямую, и их приходится эмулировать посредством монад (как в языке Haskell) или уникальных типов[en] (как в языке Clean). Это исключает любое непредсказуемое поведение отложенных вычислений, когда значения переменных изменяются раньше, чем используются.

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

Haskell — наиболее известный язык, использующий вызов по необходимости. R также использует своего рода вызов по необходимости. .NET-языки могут симулировать вызов по необходимости, используя тип Lazy<T>.

Вызов по макрораскрытию

Вызов-по-макрораскрытию (англ. call-by-macro-expansion) похож на вызов по имени, но использует текстовую подстановку вместо подстановки без захвата. При неосторожном использовании, подстановка макроопределения может привести к захвату переменной и нежелательному поведению программы. Гигиенические макроопределения[en] устраняют эту проблему, проверяя и при необходимости подменяя затеняемые переменные, не являющиеся параметрами.

Недетерминированные стратегии

Полная β-редукция

В полной β-редукции любое применение функции может быть редуцировано (подставляя аргумент в тело функции с использованием подстановки, препятствующей захвату[en] в любое время. Это может производиться даже в теле неприменённой функции.

Вызов по преднамеченности (call by future)

Вызов по преднамеченности (англ. call by future), или параллельный вызов по имени (parallel call-by-name) — это параллельная стратегия вычисления: значения преднамеченных[en] выражений (future expressions) вычисляются параллельно с течением остальной программы. В местах, где требуется значение преднамеченности, основная программа блокируется до завершения вычисления, если оно ещё не было завершено к этому моменту.

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

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

Оптимистичные вычисления

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

См. также

Напишите отзыв о статье "Стратегия вычисления"

Примечания

  1. Essentials of Programming Languages by Daniel P. Friedman and Mitchell Wand, MIT Press 1989—2006
  2. [www.cs.uiowa.edu/~hzhang/c123/Lecture5.pdf Lambda Calculus]. Cs.uiowa.edu.
  3. [encyclopedia2.thefreedictionary.com/applicative+order+reduction applicative order reduction definition of applicative order reduction in the Free Online Encyclopedia]. Encyclopedia2.thefreedictionary.com.
  4. Barbara Liskov, Russ Atkinson, Toby Bloom, Eliot Moss, Craig Schaffert, Craig Scheifler, Alan Snyder. [www.lcs.mit.edu/publications/pubs/pdf/MIT-LCS-TR-225.pdf CLU Reference Manual] ( (англ.)). Laboratory for Computer Science. Massachusetts Institute of Technology (1979).
  5. Fredrik Lundh. [effbot.org/zone/call-by-object.htm Call By Object] ( (англ.)). effbot.org.
  6. [www.cs.cornell.edu/courses/cs412/2001sp/iota/iota.html Iota Language Definition]. CS 412/413 Introduction to Compilers. Cornell University (2001).
  7. [msdn.microsoft.com/en-us/library/ms182131.aspx CA1021: Avoid out parameters]
  8. В отличие от Си, в Python записи «l += x» и «l = l + x» не являются эквивалентными — первое семантически является изменением, а не присваиванием. Более того, «l += x» не является синтаксическим эквивалентом «l.extend(x)» из-за правил разрешения видимости: «l += x» требует, чтобы «l» был в локальной области, тогда как «l.extend(x)» ищет также и в охватывающих.

Ссылки

  • Харольд Абельсон, Джеральд Джей Сассман, Джули Сассман — Структура и интерпретация компьютерных программ
  • Clem Baker-Finch, David King, Jon Hall, Phil Trinder [cs.anu.edu.au/people/Clem.Baker-Finch/Research/par-cbn-tr/ An Operational Semantics for Parallel Call-by-Need] // Research report. — Faculty of Mathematics & Computing, The Open University, 1999-03-10. — Вып. 1. — № 99.
  • Robert Ennals, Simon Peyton Jones [research.microsoft.com/en-us/um/people/simonpj/Papers/optimistic/icfp2003.pdf Optimistic Evaluation: a fast evaluation strategy for non-strict programs]. — ACM Press, 2003. — Вып. International Conference on Functional Programming.
  • Bertram Ludäscher. [users.sdsc.edu/~ludaesch/CSE130/ln5.html CSE 130 lecture notes] ( (англ.)). CSE 130: Programming Languages: Principles & Paradigms (24 января 2001).
  • Benjamin C. Pierce. Types and Programming Languages. — MIT Press, 2002. — ISBN 978-0-262-16209-8.
  • Peter Sestoft. [www.dina.kvl.dk/~sestoft/papers/sestoft-lamreduce.pdf The essence of computation : complexity, analysis, trnasformation : essays dedicated to Neil D. Jones]. — Springer-Verlag, 2002. — С. 420–435 "Demonstrating Lambda Calculus Reduction". — ISBN 3-540-00326-6.

Отрывок, характеризующий Стратегия вычисления

Князь Андрей не успел отвечать ему. Слуги вышли навстречу, и он расспрашивал о том, где был старый князь и скоро ли ждут его.
Старый князь был еще в городе, и его ждали каждую минуту.
Князь Андрей провел Пьера на свою половину, всегда в полной исправности ожидавшую его в доме его отца, и сам пошел в детскую.
– Пойдем к сестре, – сказал князь Андрей, возвратившись к Пьеру; – я еще не видал ее, она теперь прячется и сидит с своими божьими людьми. Поделом ей, она сконфузится, а ты увидишь божьих людей. C'est curieux, ma parole. [Это любопытно, честное слово.]
– Qu'est ce que c'est que [Что такое] божьи люди? – спросил Пьер
– А вот увидишь.
Княжна Марья действительно сконфузилась и покраснела пятнами, когда вошли к ней. В ее уютной комнате с лампадами перед киотами, на диване, за самоваром сидел рядом с ней молодой мальчик с длинным носом и длинными волосами, и в монашеской рясе.
На кресле, подле, сидела сморщенная, худая старушка с кротким выражением детского лица.
– Andre, pourquoi ne pas m'avoir prevenu? [Андрей, почему не предупредили меня?] – сказала она с кротким упреком, становясь перед своими странниками, как наседка перед цыплятами.
– Charmee de vous voir. Je suis tres contente de vous voir, [Очень рада вас видеть. Я так довольна, что вижу вас,] – сказала она Пьеру, в то время, как он целовал ее руку. Она знала его ребенком, и теперь дружба его с Андреем, его несчастие с женой, а главное, его доброе, простое лицо расположили ее к нему. Она смотрела на него своими прекрасными, лучистыми глазами и, казалось, говорила: «я вас очень люблю, но пожалуйста не смейтесь над моими ». Обменявшись первыми фразами приветствия, они сели.
– А, и Иванушка тут, – сказал князь Андрей, указывая улыбкой на молодого странника.
– Andre! – умоляюще сказала княжна Марья.
– Il faut que vous sachiez que c'est une femme, [Знай, что это женщина,] – сказал Андрей Пьеру.
– Andre, au nom de Dieu! [Андрей, ради Бога!] – повторила княжна Марья.
Видно было, что насмешливое отношение князя Андрея к странникам и бесполезное заступничество за них княжны Марьи были привычные, установившиеся между ними отношения.
– Mais, ma bonne amie, – сказал князь Андрей, – vous devriez au contraire m'etre reconaissante de ce que j'explique a Pierre votre intimite avec ce jeune homme… [Но, мой друг, ты должна бы быть мне благодарна, что я объясняю Пьеру твою близость к этому молодому человеку.]
– Vraiment? [Правда?] – сказал Пьер любопытно и серьезно (за что особенно ему благодарна была княжна Марья) вглядываясь через очки в лицо Иванушки, который, поняв, что речь шла о нем, хитрыми глазами оглядывал всех.
Княжна Марья совершенно напрасно смутилась за своих. Они нисколько не робели. Старушка, опустив глаза, но искоса поглядывая на вошедших, опрокинув чашку вверх дном на блюдечко и положив подле обкусанный кусочек сахара, спокойно и неподвижно сидела на своем кресле, ожидая, чтобы ей предложили еще чаю. Иванушка, попивая из блюдечка, исподлобья лукавыми, женскими глазами смотрел на молодых людей.
– Где, в Киеве была? – спросил старуху князь Андрей.
– Была, отец, – отвечала словоохотливо старуха, – на самое Рожество удостоилась у угодников сообщиться святых, небесных тайн. А теперь из Колязина, отец, благодать великая открылась…
– Что ж, Иванушка с тобой?
– Я сам по себе иду, кормилец, – стараясь говорить басом, сказал Иванушка. – Только в Юхнове с Пелагеюшкой сошлись…
Пелагеюшка перебила своего товарища; ей видно хотелось рассказать то, что она видела.
– В Колязине, отец, великая благодать открылась.
– Что ж, мощи новые? – спросил князь Андрей.
– Полно, Андрей, – сказала княжна Марья. – Не рассказывай, Пелагеюшка.
– Ни… что ты, мать, отчего не рассказывать? Я его люблю. Он добрый, Богом взысканный, он мне, благодетель, рублей дал, я помню. Как была я в Киеве и говорит мне Кирюша юродивый – истинно Божий человек, зиму и лето босой ходит. Что ходишь, говорит, не по своему месту, в Колязин иди, там икона чудотворная, матушка пресвятая Богородица открылась. Я с тех слов простилась с угодниками и пошла…
Все молчали, одна странница говорила мерным голосом, втягивая в себя воздух.
– Пришла, отец мой, мне народ и говорит: благодать великая открылась, у матушки пресвятой Богородицы миро из щечки каплет…
– Ну хорошо, хорошо, после расскажешь, – краснея сказала княжна Марья.
– Позвольте у нее спросить, – сказал Пьер. – Ты сама видела? – спросил он.
– Как же, отец, сама удостоилась. Сияние такое на лике то, как свет небесный, а из щечки у матушки так и каплет, так и каплет…
– Да ведь это обман, – наивно сказал Пьер, внимательно слушавший странницу.
– Ах, отец, что говоришь! – с ужасом сказала Пелагеюшка, за защитой обращаясь к княжне Марье.
– Это обманывают народ, – повторил он.
– Господи Иисусе Христе! – крестясь сказала странница. – Ох, не говори, отец. Так то один анарал не верил, сказал: «монахи обманывают», да как сказал, так и ослеп. И приснилось ему, что приходит к нему матушка Печерская и говорит: «уверуй мне, я тебя исцелю». Вот и стал проситься: повези да повези меня к ней. Это я тебе истинную правду говорю, сама видела. Привезли его слепого прямо к ней, подошел, упал, говорит: «исцели! отдам тебе, говорит, в чем царь жаловал». Сама видела, отец, звезда в ней так и вделана. Что ж, – прозрел! Грех говорить так. Бог накажет, – поучительно обратилась она к Пьеру.
– Как же звезда то в образе очутилась? – спросил Пьер.
– В генералы и матушку произвели? – сказал князь Aндрей улыбаясь.
Пелагеюшка вдруг побледнела и всплеснула руками.
– Отец, отец, грех тебе, у тебя сын! – заговорила она, из бледности вдруг переходя в яркую краску.
– Отец, что ты сказал такое, Бог тебя прости. – Она перекрестилась. – Господи, прости его. Матушка, что ж это?… – обратилась она к княжне Марье. Она встала и чуть не плача стала собирать свою сумочку. Ей, видно, было и страшно, и стыдно, что она пользовалась благодеяниями в доме, где могли говорить это, и жалко, что надо было теперь лишиться благодеяний этого дома.
– Ну что вам за охота? – сказала княжна Марья. – Зачем вы пришли ко мне?…
– Нет, ведь я шучу, Пелагеюшка, – сказал Пьер. – Princesse, ma parole, je n'ai pas voulu l'offenser, [Княжна, я право, не хотел обидеть ее,] я так только. Ты не думай, я пошутил, – говорил он, робко улыбаясь и желая загладить свою вину. – Ведь это я, а он так, пошутил только.
Пелагеюшка остановилась недоверчиво, но в лице Пьера была такая искренность раскаяния, и князь Андрей так кротко смотрел то на Пелагеюшку, то на Пьера, что она понемногу успокоилась.


Странница успокоилась и, наведенная опять на разговор, долго потом рассказывала про отца Амфилохия, который был такой святой жизни, что от ручки его ладоном пахло, и о том, как знакомые ей монахи в последнее ее странствие в Киев дали ей ключи от пещер, и как она, взяв с собой сухарики, двое суток провела в пещерах с угодниками. «Помолюсь одному, почитаю, пойду к другому. Сосну, опять пойду приложусь; и такая, матушка, тишина, благодать такая, что и на свет Божий выходить не хочется».
Пьер внимательно и серьезно слушал ее. Князь Андрей вышел из комнаты. И вслед за ним, оставив божьих людей допивать чай, княжна Марья повела Пьера в гостиную.
– Вы очень добры, – сказала она ему.
– Ах, я право не думал оскорбить ее, я так понимаю и высоко ценю эти чувства!
Княжна Марья молча посмотрела на него и нежно улыбнулась. – Ведь я вас давно знаю и люблю как брата, – сказала она. – Как вы нашли Андрея? – спросила она поспешно, не давая ему времени сказать что нибудь в ответ на ее ласковые слова. – Он очень беспокоит меня. Здоровье его зимой лучше, но прошлой весной рана открылась, и доктор сказал, что он должен ехать лечиться. И нравственно я очень боюсь за него. Он не такой характер как мы, женщины, чтобы выстрадать и выплакать свое горе. Он внутри себя носит его. Нынче он весел и оживлен; но это ваш приезд так подействовал на него: он редко бывает таким. Ежели бы вы могли уговорить его поехать за границу! Ему нужна деятельность, а эта ровная, тихая жизнь губит его. Другие не замечают, а я вижу.
В 10 м часу официанты бросились к крыльцу, заслышав бубенчики подъезжавшего экипажа старого князя. Князь Андрей с Пьером тоже вышли на крыльцо.
– Это кто? – спросил старый князь, вылезая из кареты и угадав Пьера.
– AI очень рад! целуй, – сказал он, узнав, кто был незнакомый молодой человек.
Старый князь был в хорошем духе и обласкал Пьера.
Перед ужином князь Андрей, вернувшись назад в кабинет отца, застал старого князя в горячем споре с Пьером.
Пьер доказывал, что придет время, когда не будет больше войны. Старый князь, подтрунивая, но не сердясь, оспаривал его.
– Кровь из жил выпусти, воды налей, тогда войны не будет. Бабьи бредни, бабьи бредни, – проговорил он, но всё таки ласково потрепал Пьера по плечу, и подошел к столу, у которого князь Андрей, видимо не желая вступать в разговор, перебирал бумаги, привезенные князем из города. Старый князь подошел к нему и стал говорить о делах.
– Предводитель, Ростов граф, половины людей не доставил. Приехал в город, вздумал на обед звать, – я ему такой обед задал… А вот просмотри эту… Ну, брат, – обратился князь Николай Андреич к сыну, хлопая по плечу Пьера, – молодец твой приятель, я его полюбил! Разжигает меня. Другой и умные речи говорит, а слушать не хочется, а он и врет да разжигает меня старика. Ну идите, идите, – сказал он, – может быть приду, за ужином вашим посижу. Опять поспорю. Мою дуру, княжну Марью полюби, – прокричал он Пьеру из двери.
Пьер теперь только, в свой приезд в Лысые Горы, оценил всю силу и прелесть своей дружбы с князем Андреем. Эта прелесть выразилась не столько в его отношениях с ним самим, сколько в отношениях со всеми родными и домашними. Пьер с старым, суровым князем и с кроткой и робкой княжной Марьей, несмотря на то, что он их почти не знал, чувствовал себя сразу старым другом. Они все уже любили его. Не только княжна Марья, подкупленная его кроткими отношениями к странницам, самым лучистым взглядом смотрела на него; но маленький, годовой князь Николай, как звал дед, улыбнулся Пьеру и пошел к нему на руки. Михаил Иваныч, m lle Bourienne с радостными улыбками смотрели на него, когда он разговаривал с старым князем.
Старый князь вышел ужинать: это было очевидно для Пьера. Он был с ним оба дня его пребывания в Лысых Горах чрезвычайно ласков, и велел ему приезжать к себе.
Когда Пьер уехал и сошлись вместе все члены семьи, его стали судить, как это всегда бывает после отъезда нового человека и, как это редко бывает, все говорили про него одно хорошее.


Возвратившись в этот раз из отпуска, Ростов в первый раз почувствовал и узнал, до какой степени сильна была его связь с Денисовым и со всем полком.
Когда Ростов подъезжал к полку, он испытывал чувство подобное тому, которое он испытывал, подъезжая к Поварскому дому. Когда он увидал первого гусара в расстегнутом мундире своего полка, когда он узнал рыжего Дементьева, увидал коновязи рыжих лошадей, когда Лаврушка радостно закричал своему барину: «Граф приехал!» и лохматый Денисов, спавший на постели, выбежал из землянки, обнял его, и офицеры сошлись к приезжему, – Ростов испытывал такое же чувство, как когда его обнимала мать, отец и сестры, и слезы радости, подступившие ему к горлу, помешали ему говорить. Полк был тоже дом, и дом неизменно милый и дорогой, как и дом родительский.
Явившись к полковому командиру, получив назначение в прежний эскадрон, сходивши на дежурство и на фуражировку, войдя во все маленькие интересы полка и почувствовав себя лишенным свободы и закованным в одну узкую неизменную рамку, Ростов испытал то же успокоение, ту же опору и то же сознание того, что он здесь дома, на своем месте, которые он чувствовал и под родительским кровом. Не было этой всей безурядицы вольного света, в котором он не находил себе места и ошибался в выборах; не было Сони, с которой надо было или не надо было объясняться. Не было возможности ехать туда или не ехать туда; не было этих 24 часов суток, которые столькими различными способами можно было употребить; не было этого бесчисленного множества людей, из которых никто не был ближе, никто не был дальше; не было этих неясных и неопределенных денежных отношений с отцом, не было напоминания об ужасном проигрыше Долохову! Тут в полку всё было ясно и просто. Весь мир был разделен на два неровные отдела. Один – наш Павлоградский полк, и другой – всё остальное. И до этого остального не было никакого дела. В полку всё было известно: кто был поручик, кто ротмистр, кто хороший, кто дурной человек, и главное, – товарищ. Маркитант верит в долг, жалованье получается в треть; выдумывать и выбирать нечего, только не делай ничего такого, что считается дурным в Павлоградском полку; а пошлют, делай то, что ясно и отчетливо, определено и приказано: и всё будет хорошо.
Вступив снова в эти определенные условия полковой жизни, Ростов испытал радость и успокоение, подобные тем, которые чувствует усталый человек, ложась на отдых. Тем отраднее была в эту кампанию эта полковая жизнь Ростову, что он, после проигрыша Долохову (поступка, которого он, несмотря на все утешения родных, не мог простить себе), решился служить не как прежде, а чтобы загладить свою вину, служить хорошо и быть вполне отличным товарищем и офицером, т. е. прекрасным человеком, что представлялось столь трудным в миру, а в полку столь возможным.
Ростов, со времени своего проигрыша, решил, что он в пять лет заплатит этот долг родителям. Ему посылалось по 10 ти тысяч в год, теперь же он решился брать только две, а остальные предоставлять родителям для уплаты долга.

Армия наша после неоднократных отступлений, наступлений и сражений при Пултуске, при Прейсиш Эйлау, сосредоточивалась около Бартенштейна. Ожидали приезда государя к армии и начала новой кампании.
Павлоградский полк, находившийся в той части армии, которая была в походе 1805 года, укомплектовываясь в России, опоздал к первым действиям кампании. Он не был ни под Пултуском, ни под Прейсиш Эйлау и во второй половине кампании, присоединившись к действующей армии, был причислен к отряду Платова.
Отряд Платова действовал независимо от армии. Несколько раз павлоградцы были частями в перестрелках с неприятелем, захватили пленных и однажды отбили даже экипажи маршала Удино. В апреле месяце павлоградцы несколько недель простояли около разоренной до тла немецкой пустой деревни, не трогаясь с места.
Была ростепель, грязь, холод, реки взломало, дороги сделались непроездны; по нескольку дней не выдавали ни лошадям ни людям провианта. Так как подвоз сделался невозможен, то люди рассыпались по заброшенным пустынным деревням отыскивать картофель, но уже и того находили мало. Всё было съедено, и все жители разбежались; те, которые оставались, были хуже нищих, и отнимать у них уж было нечего, и даже мало – жалостливые солдаты часто вместо того, чтобы пользоваться от них, отдавали им свое последнее.
Павлоградский полк в делах потерял только двух раненых; но от голоду и болезней потерял почти половину людей. В госпиталях умирали так верно, что солдаты, больные лихорадкой и опухолью, происходившими от дурной пищи, предпочитали нести службу, через силу волоча ноги во фронте, чем отправляться в больницы. С открытием весны солдаты стали находить показывавшееся из земли растение, похожее на спаржу, которое они называли почему то машкин сладкий корень, и рассыпались по лугам и полям, отыскивая этот машкин сладкий корень (который был очень горек), саблями выкапывали его и ели, несмотря на приказания не есть этого вредного растения.
Весною между солдатами открылась новая болезнь, опухоль рук, ног и лица, причину которой медики полагали в употреблении этого корня. Но несмотря на запрещение, павлоградские солдаты эскадрона Денисова ели преимущественно машкин сладкий корень, потому что уже вторую неделю растягивали последние сухари, выдавали только по полфунта на человека, а картофель в последнюю посылку привезли мерзлый и проросший. Лошади питались тоже вторую неделю соломенными крышами с домов, были безобразно худы и покрыты еще зимнею, клоками сбившеюся шерстью.
Несмотря на такое бедствие, солдаты и офицеры жили точно так же, как и всегда; так же и теперь, хотя и с бледными и опухлыми лицами и в оборванных мундирах, гусары строились к расчетам, ходили на уборку, чистили лошадей, амуницию, таскали вместо корма солому с крыш и ходили обедать к котлам, от которых вставали голодные, подшучивая над своею гадкой пищей и своим голодом. Также как и всегда, в свободное от службы время солдаты жгли костры, парились голые у огней, курили, отбирали и пекли проросший, прелый картофель и рассказывали и слушали рассказы или о Потемкинских и Суворовских походах, или сказки об Алеше пройдохе, и о поповом батраке Миколке.
Офицеры так же, как и обыкновенно, жили по двое, по трое, в раскрытых полуразоренных домах. Старшие заботились о приобретении соломы и картофеля, вообще о средствах пропитания людей, младшие занимались, как всегда, кто картами (денег было много, хотя провианта и не было), кто невинными играми – в свайку и городки. Об общем ходе дел говорили мало, частью оттого, что ничего положительного не знали, частью оттого, что смутно чувствовали, что общее дело войны шло плохо.
Ростов жил, попрежнему, с Денисовым, и дружеская связь их, со времени их отпуска, стала еще теснее. Денисов никогда не говорил про домашних Ростова, но по нежной дружбе, которую командир оказывал своему офицеру, Ростов чувствовал, что несчастная любовь старого гусара к Наташе участвовала в этом усилении дружбы. Денисов видимо старался как можно реже подвергать Ростова опасностям, берег его и после дела особенно радостно встречал его целым и невредимым. На одной из своих командировок Ростов нашел в заброшенной разоренной деревне, куда он приехал за провиантом, семейство старика поляка и его дочери, с грудным ребенком. Они были раздеты, голодны, и не могли уйти, и не имели средств выехать. Ростов привез их в свою стоянку, поместил в своей квартире, и несколько недель, пока старик оправлялся, содержал их. Товарищ Ростова, разговорившись о женщинах, стал смеяться Ростову, говоря, что он всех хитрее, и что ему бы не грех познакомить товарищей с спасенной им хорошенькой полькой. Ростов принял шутку за оскорбление и, вспыхнув, наговорил офицеру таких неприятных вещей, что Денисов с трудом мог удержать обоих от дуэли. Когда офицер ушел и Денисов, сам не знавший отношений Ростова к польке, стал упрекать его за вспыльчивость, Ростов сказал ему:
– Как же ты хочешь… Она мне, как сестра, и я не могу тебе описать, как это обидно мне было… потому что… ну, оттого…
Денисов ударил его по плечу, и быстро стал ходить по комнате, не глядя на Ростова, что он делывал в минуты душевного волнения.
– Экая дуг'ацкая ваша пог'ода Г'остовская, – проговорил он, и Ростов заметил слезы на глазах Денисова.


В апреле месяце войска оживились известием о приезде государя к армии. Ростову не удалось попасть на смотр который делал государь в Бартенштейне: павлоградцы стояли на аванпостах, далеко впереди Бартенштейна.
Они стояли биваками. Денисов с Ростовым жили в вырытой для них солдатами землянке, покрытой сучьями и дерном. Землянка была устроена следующим, вошедшим тогда в моду, способом: прорывалась канава в полтора аршина ширины, два – глубины и три с половиной длины. С одного конца канавы делались ступеньки, и это был сход, крыльцо; сама канава была комната, в которой у счастливых, как у эскадронного командира, в дальней, противуположной ступеням стороне, лежала на кольях, доска – это был стол. С обеих сторон вдоль канавы была снята на аршин земля, и это были две кровати и диваны. Крыша устраивалась так, что в середине можно было стоять, а на кровати даже можно было сидеть, ежели подвинуться ближе к столу. У Денисова, жившего роскошно, потому что солдаты его эскадрона любили его, была еще доска в фронтоне крыши, и в этой доске было разбитое, но склеенное стекло. Когда было очень холодно, то к ступеням (в приемную, как называл Денисов эту часть балагана), приносили на железном загнутом листе жар из солдатских костров, и делалось так тепло, что офицеры, которых много всегда бывало у Денисова и Ростова, сидели в одних рубашках.
В апреле месяце Ростов был дежурным. В 8 м часу утра, вернувшись домой, после бессонной ночи, он велел принести жару, переменил измокшее от дождя белье, помолился Богу, напился чаю, согрелся, убрал в порядок вещи в своем уголке и на столе, и с обветрившимся, горевшим лицом, в одной рубашке, лег на спину, заложив руки под голову. Он приятно размышлял о том, что на днях должен выйти ему следующий чин за последнюю рекогносцировку, и ожидал куда то вышедшего Денисова. Ростову хотелось поговорить с ним.
За шалашом послышался перекатывающийся крик Денисова, очевидно разгорячившегося. Ростов подвинулся к окну посмотреть, с кем он имел дело, и увидал вахмистра Топчеенко.
– Я тебе пг'иказывал не пускать их жг'ать этот ког'ень, машкин какой то! – кричал Денисов. – Ведь я сам видел, Лазаг'чук с поля тащил.
– Я приказывал, ваше высокоблагородие, не слушают, – отвечал вахмистр.
Ростов опять лег на свою кровать и с удовольствием подумал: «пускай его теперь возится, хлопочет, я свое дело отделал и лежу – отлично!» Из за стенки он слышал, что, кроме вахмистра, еще говорил Лаврушка, этот бойкий плутоватый лакей Денисова. Лаврушка что то рассказывал о каких то подводах, сухарях и быках, которых он видел, ездивши за провизией.
За балаганом послышался опять удаляющийся крик Денисова и слова: «Седлай! Второй взвод!»
«Куда это собрались?» подумал Ростов.
Через пять минут Денисов вошел в балаган, влез с грязными ногами на кровать, сердито выкурил трубку, раскидал все свои вещи, надел нагайку и саблю и стал выходить из землянки. На вопрос Ростова, куда? он сердито и неопределенно отвечал, что есть дело.
– Суди меня там Бог и великий государь! – сказал Денисов, выходя; и Ростов услыхал, как за балаганом зашлепали по грязи ноги нескольких лошадей. Ростов не позаботился даже узнать, куда поехал Денисов. Угревшись в своем угле, он заснул и перед вечером только вышел из балагана. Денисов еще не возвращался. Вечер разгулялся; около соседней землянки два офицера с юнкером играли в свайку, с смехом засаживая редьки в рыхлую грязную землю. Ростов присоединился к ним. В середине игры офицеры увидали подъезжавшие к ним повозки: человек 15 гусар на худых лошадях следовали за ними. Повозки, конвоируемые гусарами, подъехали к коновязям, и толпа гусар окружила их.
– Ну вот Денисов всё тужил, – сказал Ростов, – вот и провиант прибыл.
– И то! – сказали офицеры. – То то радешеньки солдаты! – Немного позади гусар ехал Денисов, сопутствуемый двумя пехотными офицерами, с которыми он о чем то разговаривал. Ростов пошел к нему навстречу.
– Я вас предупреждаю, ротмистр, – говорил один из офицеров, худой, маленький ростом и видимо озлобленный.
– Ведь сказал, что не отдам, – отвечал Денисов.
– Вы будете отвечать, ротмистр, это буйство, – у своих транспорты отбивать! Наши два дня не ели.
– А мои две недели не ели, – отвечал Денисов.
– Это разбой, ответите, милостивый государь! – возвышая голос, повторил пехотный офицер.
– Да вы что ко мне пристали? А? – крикнул Денисов, вдруг разгорячась, – отвечать буду я, а не вы, а вы тут не жужжите, пока целы. Марш! – крикнул он на офицеров.
– Хорошо же! – не робея и не отъезжая, кричал маленький офицер, – разбойничать, так я вам…
– К чог'ту марш скорым шагом, пока цел. – И Денисов повернул лошадь к офицеру.
– Хорошо, хорошо, – проговорил офицер с угрозой, и, повернув лошадь, поехал прочь рысью, трясясь на седле.
– Собака на забог'е, живая собака на забог'е, – сказал Денисов ему вслед – высшую насмешку кавалериста над верховым пехотным, и, подъехав к Ростову, расхохотался.
– Отбил у пехоты, отбил силой транспорт! – сказал он. – Что ж, не с голоду же издыхать людям?
Повозки, которые подъехали к гусарам были назначены в пехотный полк, но, известившись через Лаврушку, что этот транспорт идет один, Денисов с гусарами силой отбил его. Солдатам раздали сухарей в волю, поделились даже с другими эскадронами.
На другой день, полковой командир позвал к себе Денисова и сказал ему, закрыв раскрытыми пальцами глаза: «Я на это смотрю вот так, я ничего не знаю и дела не начну; но советую съездить в штаб и там, в провиантском ведомстве уладить это дело, и, если возможно, расписаться, что получили столько то провианту; в противном случае, требованье записано на пехотный полк: дело поднимется и может кончиться дурно».