воскресенье, 20 июня 2010 г.

Постановка, исходник, комментарий

Покажем, что постановка задачи оторвана от исходника, точнее в другую сторону (исходник от задачи).

В cs есть такая теорема Райса (Райса-Шапиро, в некоторых вариациях встречается фамилия Успенского, но может быть это уже оффтопик). По исходному коду нельзя понять никакие нетривиальные свойства вычисляемого алгоритма. "Как же так ?" - спросит читатель. Вот исходник, сейчас почешу голову и пойму как оно все там работает.

Перейдем к примерам. Вот, например, некий код (уж извините, императивщина):

Pair[int, int] Some(int a, int b)
{
 int p;
 p = b;
 while (a > p)
 {
  p *= 2;
 }
 int q = 0;
 while (p != b)
 {
  p /= 2;
  q *= 2;
  if (a > p)
  {
   a -= p;
   q++;
  }
 }

 return [q, a];
}

Делается ли здесь что-либо полезное?

Some(56, 8) = [6, 8]

Фиг его знает. Я не фиг, я не знаю (странный логический вывод). Если вы найдете смысл в этой программе - сообщите мне (подумайте с полчаса).

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

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

Давайте рандомом поменяем два символа в исходнике.

Pair[int, int] Some1(int a, int b)
{
 int p;
 p = b;
 while (a >= p)
 {
  p *= 2;
 }
 int q = 0;
 while (p != b)
 {
  p /= 2;
  q *= 2;
  if (a >= p)
  {
   a -= p;
   q++;
  }
 }

 return [q, a];
}

Найдите два отличия (даже три) :) .

А сейчас есть ли смысл у программы? Еще раз - конечно, нет. Есть ли смысл у мясорубки? Она тупо делает фарш из всего, что ей подадут на вход. И из мяса, и из хлеба, и из карандашей (если их подать на вход). Так и программа - тупо исполняет то, что в ней написано.

Но приведем несколько тестов
Some(56, 8) = [7, 0]
Some(25, 4) = [6, 1]
Тут уже можно заметить закономерность. Внезапно, программа начала делить нацело числа! Подумайте с полчаса, как же это работает.

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

А вот если бы у нас была постановка задачи ранее исходников, то кое что можно было бы сказать. Заметим, что вторая программа не идеальна: деление на 0, деление только натуральных, возможен глюк при переполнении p (p *= 2;)

Так вот, из исходного кода получить постановку (Райс-Шапиро - нельзя) (я - трудновато :) ). То есть желательно двигаться от постановки задачи к исходнику. А это уже синтез программ, и тут лет на n*10 пока глуховато.

Итого, мы пришли что двигаться от программы к постановке (смыслу?) очень трудно.

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

Не могу сказать, что полностью понял идею Кнутовского грамотного программирования (literate programing); а вот контрактное программирование (Мейера, Eiffel) близко к пред/пост-условиям, и мне по душе. Текущее состояние с текстовыми комментариями, да еще в часто изменяемом коде, выглядит страшновато. Заметим, что все быстрые agile методологии предпочитают тесты вместо комментариев.

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

Комментариев нет: