OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 19 Март, 2024 11:44

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 96 ]  На страницу 1, 2, 3, 4, 5  След.
Автор Сообщение
 Заголовок сообщения: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 06:27 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Сначала ломал голову над странными LOOP'ами. Потом обнаружил повторяющуюся схему:
Код:
LOOP
   IF A THEN
      EXIT;
   ELSIF B THEN
      OneShotCode; (* здесь может быть много строк кода *)
      EXIT;
   END;
   Step; (* здесь тоже иногда больше одной строки *)
END;
Понял, что это всё преобразуется в простой и понятный линейный поиск:
Код:
WHILE ~A & ~B DO
   Step;
END;
IF ~A THEN
   OneShotCode;
END;
В такой записи код более компактен как по числу строк, так и по уровню отступа. После преобразования понял, что было самым странным. То, что код OneShotCode находится внутри цикла, но выполняется только один раз. :twisted:


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 06:29 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Пример:
Код:
   LOOP
      IF tmp = NIL THEN
         EXIT;
      ELSIF tmp = li THEN
         IF prev = NIL THEN
            w.firstLine := li.next;
         ELSE
            prev.next := li.next;
            LOOP
               tmp := tmp.next;
               IF tmp = NIL THEN EXIT END;
               DEC (tmp.idx);
            END; (* loop *)
         END; (* if prev *)
         EXIT;
      END; (* if tmp *)
      INC (py, tmp.height); prev := tmp; tmp := tmp.next;
   END; (* loop *)
Код:
   WHILE (tmp # NIL) & (tmp # li) DO
      INC (py, tmp.height); prev := tmp; tmp := tmp.next;
   END;
   IF tmp # NIL THEN
      IF prev = NIL THEN
         w.firstLine := li.next;
      ELSE
         prev.next := li.next;
         tmp := tmp.next;
         WHILE tmp # NIL DO
            DEC (tmp.idx);
            tmp := tmp.next;
         END;
      END; (* if prev *)
   END; (* if found tmp = li *)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 07:38 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Ещё один пример:
Код:
LOOP
   Step;
   IF A THEN EXIT END;
   CodeBlock;
END;
Преобразуется в:
Код:
Step;
WHILE ~A DO
   CodeBlock;
   Step;
END;
Данная схема присутствует в предыдущем сообщении - см. вложенный LOOP.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 07:41 

Зарегистрирован: Пятница, 24 Апрель, 2009 16:28
Сообщения: 563
Откуда: Москва
Александр Ильин писал(а):
Сначала ломал голову над странными LOOP'ами. Потом обнаружил повторяющуюся схему:
Чей код-то?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 07:46 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Встречаются и тривиальные экземпляры, в которых вообще неясно, зачем было LOOP использовать:
Код:
LOOP
   IF ~ProcCall () THEN EXIT END;
   Step; (*может быть несколько строк *)
END;
Код:
WHILE ProcCall () DO
   Step; (*может быть несколько строк *)
END;


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 12:02 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Встретил вариант схемы из первого поста:
Код:
LOOP
   IF A THEN
      OneShotCode; (* здесь может быть много строк кода *)
      EXIT;
   ELSIF B THEN
      EXIT;
   END;
   Step; (* здесь тоже иногда больше одной строки *)
END;
Код:
WHILE ~A & ~B DO
   Step;
END;
IF A THEN
   OneShotCode;
END;
Отличие в том, что OneShotCode выполняется при условии A, а не B. Соответственно, после WHILE проверяется не ~A, а просто A.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 12:15 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8500
Откуда: Троицк, Москва
Александр Ильин писал(а):
Встречаются и тривиальные экземпляры, в которых вообще неясно, зачем было LOOP использовать
Как зачем? Для крутизны :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 13:30 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Вот ещё нечитабельная схема:
Код:
VAR var: BOOLEAN;
BEGIN
   var := FALSE;
   LOOP
      SomeCode (var); (* нечто многострочное, не содержащее EXIT и RETURN и не меняющее значение var *)
      IF var OR OtherConditions () THEN
         EXIT
      END;
      var := TRUE;
   END;
Поди-разгляди, что выполняется этот цикл один - максимум два раза. Цикл не нужен. SomeCode оформляется в отдельную процедуру:
Код:
VAR dummy: BOOLEAN;

   PROCEDURE SomeCode (var: BOOLEAN): BOOLEAN;
   BEGIN
      (* нечто многострочное, не содержащее EXIT и RETURN и не меняющее значение var *)
      RETURN var OR OtherConditions ()
   END SomeCode;

BEGIN
   dummy := SomeCode (FALSE) OR SomeCode (TRUE);
Значение dummy ингорируется, оно всегда = TRUE. Если не хочется заводить переменную dummy, то можно написать так (дело вкуса):
Код:
IF SomeCode (FALSE) OR SomeCode (TRUE) THEN (* do nothing *)
END;

Здесь после устранения LOOP объём кода не уменьшается, но, на мой взгляд, повышается ясность.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 14:12 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Вот ещё один странный экземпляр. Оригинал кода:
Код:
   LOOP
      IF tmp = dragLi THEN IF prev = NIL THEN w.SetFirstLine (dragLi.next) ELSE prev.next := dragLi.next END; EXIT END;
      prev := tmp; tmp := tmp.next;
   END; (* loop *)
Схема:
Код:
LOOP
   IF B THEN
      SomeCode;
      EXIT
   END;
   Step;
END;
С помощью WHILE:
Код:
WHILE ~B DO
   Step;
END;
SomeCode;
В общем-то, этот пример получается из примера первого поста подстановкой A = FALSE.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 15:11 

Зарегистрирован: Вторник, 25 Апрель, 2006 16:21
Сообщения: 2180
Откуда: Нижний Новгород
Это где такое?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 19:12 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Ещё пример, на этот раз с тремя ветками IF внутри LOOP, плюс разбавлено RETURN'ом:
Код:
LOOP
   IF A THEN
      EXIT
   ELSIF B THEN
      RETURN FALSE
   ELSIF C THEN
      EXIT
   END;
   Step;
END; (* loop *)
Преобразую:
Код:
WHILE ~A & ~B & ~C DO
   Step;
END;
IF ~A & B THEN
   RETURN FALSE
END;


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 19:48 

Зарегистрирован: Суббота, 07 Март, 2009 15:39
Сообщения: 3261
Откуда: Астрахань
Блестящий пример знания и использования ТЕХНИКИ программирования!


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 20:48 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8500
Откуда: Троицк, Москва
Валерий Лаптев писал(а):
Блестящий пример знания и использования ТЕХНИКИ программирования!
Думаю, Александр Сергеевич согласится, что техника тут где-то на уровне деления в столбик, так что блеск только на фоне общего мрака.

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


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 20:54 

Зарегистрирован: Суббота, 07 Март, 2009 15:39
Сообщения: 3261
Откуда: Астрахань
Не... Тут ВАЖНОЕ есть: конкретные примеры плохого кода и преобразованные в хороший. Это ВАЖНО! Тем более, что когда все на уровне арифметики 1 класса, а чел вдруг демонстрирует знание таблицы умножения - это выглядит как откровение.
И кстати, прекрасный пример рефакторинга - это чтобы молодежь не возникала! Самое современное слово используем... :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 21:04 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
В одном месте согласился на REPEAT..UNTIL. Первоначальный код:
Код:
LOOP IF (Files.IsDirectory * dp.attr = {}) OR ((dp.res # '.') & (dp.res # '..')) THEN RETURN FALSE ELSIF ~FindNext (dp) THEN EXIT END END;
RETURN TRUE
(Да-да, LOOP в одну строчку.)
Схема:
Код:
LOOP
   IF Condition () THEN
      RETURN FALSE
   ELSIF ~Next () THEN
      EXIT
   END
END;
RETURN TRUE
Добавил переменную результата res: BOOLEAN и получил:
Код:
REPEAT
   res := Condition ();
UNTIL res OR ~Next ();
RETURN ~res
В принципе, можно было через WHILE, но не захотелось Condition дублировать или выносить в отдельную процедуру. Вот как мог бы выглядеть WHILE:
Код:
res := Condition ();
WHILE ~res & Next () DO
   res := Condition ();
END;
RETURN ~res


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 21:11 

Зарегистрирован: Воскресенье, 06 Апрель, 2008 14:43
Сообщения: 557
Info21 писал(а):
Этот мрак
Вашу аргументацию не понял, точнее ее нет.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 21:14 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 1488
Откуда: Украина, Киев
Александр Ильин писал(а):
В одном месте согласился на REPEAT..UNTIL
И чем-же так страшен REPEAT..UNTIL? :mrgreen:


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 21:16 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Комбинированный пример:
Код:
LOOP
   p := Str.PosFrom (t, fs.dir, p);
   IF (p = Str.NotFound) OR (p = 0) THEN
      EXIT;
   ELSIF (p > 0) & (fs.dir [p - 1] = dirChar) THEN
      q := p; DEC (p);
      WHILE (p > 0) & (fs.dir [p - 1] # dirChar) DO DEC (p) END;
      Str.Delete (fs.dir, p, q - p + 3);
   END; (* if *)
   INC (p);
END; (* loop *)
Схема:
Код:
LOOP
   CodeBlock1;
   IF A THEN
      EXIT;
   ELSIF B THEN
      CodeBlock2;
   END;
   Step;
END;
Видим, что CodeBlock1 предшествует конструкции IF-EXIT, выносим его "за скобки" будущего WHILE. Не забываем продублировать после Step:
Код:
CodeBlock1;
LOOP
   IF A THEN
      EXIT;
   ELSIF B THEN
      CodeBlock2;
   END;
   Step;
   CodeBlock1;
END;
Обратим внимание, что в блоке CodeBlock2 нет EXIT'а, значит он не подходит под ранее рассмотренные схемы. Если бы EXIT был, то CodeBlock2 мы бы вынесли из WHILE и выполнили один раз после цикла. В данном же случае блок должен остаться внутри WHILE. Окончательная схема:
Код:
CodeBlock1;
WHILE ~A DO
   IF B THEN
      CodeBlock2;
   END;
   Step;
   CodeBlock1;
END;


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 21:50 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Alexey Veselovsky писал(а):
Это где такое?
Глобальному перетряхиванию подвергнута библиотека Amadeus-3, примеры берутся оттуда.
Info21 писал(а):
техника тут где-то на уровне деления в столбик
Тем не менее, заниматься подобным ранее мне не доводилось, так как LOOP отродясь не использовал. Публично делаю затем, чтобы дотошный читатель мог указать мне на ошибки. Кстати, составление схем уже само по себе хорошо помогает.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Убираю LOOP'ы
СообщениеДобавлено: Понедельник, 12 Апрель, 2010 22:12 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Фантазия автора не перестаёт удивлять. Может быть, он прочитал Паронджанова и в голове представляет ДРАКОН-схему, когда такое пишет? Схема с разорванным IF'ом:
Код:
LOOP
   IF A THEN
      EXIT
   END;
   Step;
   IF B THEN
      OneShotCode;
      EXIT
   ELSIF C THEN
      EXIT
   END;
END;
Условие A надо поставить перед циклом и в конце его:
Код:
IF ~A THEN
   LOOP
      Step;
      IF B THEN
         OneShotCode;
         EXIT
      ELSIF C OR A THEN
         EXIT
      END
   END;
END;
Далее видим, что LOOP оказался обычным REPEAT..UNTIL'ом:
Код:
IF ~A THEN
   REPEAT
      Step;
   UNTIL B OR C OR A;
   IF B THEN
      OneShotCode;
   END;
END;
Можно записать и как WHILE:
Код:
IF ~A THEN
   Step;
   WHILE ~B & ~(C OR A) DO
      Step;
   END;
   IF B THEN
      OneShotCode;
   END;
END;


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 96 ]  На страницу 1, 2, 3, 4, 5  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


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

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB