OberonCore https://forum.oberoncore.ru/ |
|
Убираю LOOP'ы https://forum.oberoncore.ru/viewtopic.php?f=82&t=2547 |
Страница 1 из 5 |
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 06:27 ] |
Заголовок сообщения: | Убираю LOOP'ы |
Сначала ломал голову над странными LOOP'ами. Потом обнаружил повторяющуюся схему: Код: LOOP Понял, что это всё преобразуется в простой и понятный линейный поиск:IF A THEN EXIT; ELSIF B THEN OneShotCode; (* здесь может быть много строк кода *) EXIT; END; Step; (* здесь тоже иногда больше одной строки *) END; Код: WHILE ~A & ~B DO В такой записи код более компактен как по числу строк, так и по уровню отступа. После преобразования понял, что было самым странным. То, что код OneShotCode находится внутри цикла, но выполняется только один раз. :twisted:
Step; END; IF ~A THEN OneShotCode; END; |
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 06:29 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Пример: Код: 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 *) |
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 07:38 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Ещё один пример: Код: LOOP Преобразуется в:Step; IF A THEN EXIT END; CodeBlock; END; Код: Step; Данная схема присутствует в предыдущем сообщении - см. вложенный LOOP.
WHILE ~A DO CodeBlock; Step; END; |
Автор: | Peter Almazov [ Понедельник, 12 Апрель, 2010 07:41 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Александр Ильин писал(а): Сначала ломал голову над странными LOOP'ами. Потом обнаружил повторяющуюся схему: Чей код-то?
|
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 07:46 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Встречаются и тривиальные экземпляры, в которых вообще неясно, зачем было LOOP использовать: Код: LOOP IF ~ProcCall () THEN EXIT END; Step; (*может быть несколько строк *) END; Код: WHILE ProcCall () DO
Step; (*может быть несколько строк *) END; |
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 12:02 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Встретил вариант схемы из первого поста: Код: LOOP IF A THEN OneShotCode; (* здесь может быть много строк кода *) EXIT; ELSIF B THEN EXIT; END; Step; (* здесь тоже иногда больше одной строки *) END; Код: WHILE ~A & ~B DO Отличие в том, что OneShotCode выполняется при условии A, а не B. Соответственно, после WHILE проверяется не ~A, а просто A.
Step; END; IF A THEN OneShotCode; END; |
Автор: | Info21 [ Понедельник, 12 Апрель, 2010 12:15 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Александр Ильин писал(а): Встречаются и тривиальные экземпляры, в которых вообще неясно, зачем было LOOP использовать Как зачем? Для крутизны
|
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 13:30 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Вот ещё нечитабельная схема: Код: VAR var: BOOLEAN; Поди-разгляди, что выполняется этот цикл один - максимум два раза. Цикл не нужен. SomeCode оформляется в отдельную процедуру:BEGIN var := FALSE; LOOP SomeCode (var); (* нечто многострочное, не содержащее EXIT и RETURN и не меняющее значение var *) IF var OR OtherConditions () THEN EXIT END; var := TRUE; END; Код: VAR dummy: BOOLEAN; Значение dummy ингорируется, оно всегда = TRUE. Если не хочется заводить переменную dummy, то можно написать так (дело вкуса):PROCEDURE SomeCode (var: BOOLEAN): BOOLEAN; BEGIN (* нечто многострочное, не содержащее EXIT и RETURN и не меняющее значение var *) RETURN var OR OtherConditions () END SomeCode; BEGIN dummy := SomeCode (FALSE) OR SomeCode (TRUE); Код: IF SomeCode (FALSE) OR SomeCode (TRUE) THEN (* do nothing *) END; Здесь после устранения LOOP объём кода не уменьшается, но, на мой взгляд, повышается ясность. |
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 14:12 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Вот ещё один странный экземпляр. Оригинал кода: Код: 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 С помощью WHILE:IF B THEN SomeCode; EXIT END; Step; END; Код: WHILE ~B DO В общем-то, этот пример получается из примера первого поста подстановкой A = FALSE.
Step; END; SomeCode; |
Автор: | Alexey Veselovsky [ Понедельник, 12 Апрель, 2010 15:11 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Это где такое? |
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 19:12 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Ещё пример, на этот раз с тремя ветками 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; |
Автор: | Валерий Лаптев [ Понедельник, 12 Апрель, 2010 19:48 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Блестящий пример знания и использования ТЕХНИКИ программирования! |
Автор: | Info21 [ Понедельник, 12 Апрель, 2010 20:48 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Валерий Лаптев писал(а): Блестящий пример знания и использования ТЕХНИКИ программирования! Думаю, Александр Сергеевич согласится, что техника тут где-то на уровне деления в столбик, так что блеск только на фоне общего мрака.Этот мрак -- такой архилюбопытный антропологический феномен, что даже раздел на форуме заведен. |
Автор: | Валерий Лаптев [ Понедельник, 12 Апрель, 2010 20:54 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Не... Тут ВАЖНОЕ есть: конкретные примеры плохого кода и преобразованные в хороший. Это ВАЖНО! Тем более, что когда все на уровне арифметики 1 класса, а чел вдруг демонстрирует знание таблицы умножения - это выглядит как откровение. И кстати, прекрасный пример рефакторинга - это чтобы молодежь не возникала! Самое современное слово используем... |
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 21:04 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
В одном месте согласился на REPEAT..UNTIL. Первоначальный код: Код: LOOP IF (Files.IsDirectory * dp.attr = {}) OR ((dp.res # '.') & (dp.res # '..')) THEN RETURN FALSE ELSIF ~FindNext (dp) THEN EXIT END END; (Да-да, LOOP в одну строчку.)RETURN TRUE Схема: Код: LOOP Добавил переменную результата res: BOOLEAN и получил:IF Condition () THEN RETURN FALSE ELSIF ~Next () THEN EXIT END END; RETURN TRUE Код: REPEAT В принципе, можно было через WHILE, но не захотелось Condition дублировать или выносить в отдельную процедуру. Вот как мог бы выглядеть WHILE:res := Condition (); UNTIL res OR ~Next (); RETURN ~res Код: res := Condition ();
WHILE ~res & Next () DO res := Condition (); END; RETURN ~res |
Автор: | ==== [ Понедельник, 12 Апрель, 2010 21:11 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Info21 писал(а): Этот мрак Вашу аргументацию не понял, точнее ее нет.
|
Автор: | Ярослав Романченко [ Понедельник, 12 Апрель, 2010 21:14 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Александр Ильин писал(а): В одном месте согласился на REPEAT..UNTIL И чем-же так страшен REPEAT..UNTIL?
|
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 21:16 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Комбинированный пример: Код: 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-EXIT, выносим его "за скобки" будущего WHILE. Не забываем продублировать после Step:CodeBlock1; IF A THEN EXIT; ELSIF B THEN CodeBlock2; END; Step; END; Код: CodeBlock1; Обратим внимание, что в блоке CodeBlock2 нет EXIT'а, значит он не подходит под ранее рассмотренные схемы. Если бы EXIT был, то CodeBlock2 мы бы вынесли из WHILE и выполнили один раз после цикла. В данном же случае блок должен остаться внутри WHILE. Окончательная схема:LOOP IF A THEN EXIT; ELSIF B THEN CodeBlock2; END; Step; CodeBlock1; END; Код: CodeBlock1;
WHILE ~A DO IF B THEN CodeBlock2; END; Step; CodeBlock1; END; |
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 21:50 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Alexey Veselovsky писал(а): Это где такое? Глобальному перетряхиванию подвергнута библиотека Amadeus-3, примеры берутся оттуда.Info21 писал(а): техника тут где-то на уровне деления в столбик Тем не менее, заниматься подобным ранее мне не доводилось, так как LOOP отродясь не использовал. Публично делаю затем, чтобы дотошный читатель мог указать мне на ошибки. Кстати, составление схем уже само по себе хорошо помогает.
|
Автор: | Александр Ильин [ Понедельник, 12 Апрель, 2010 22:12 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Фантазия автора не перестаёт удивлять. Может быть, он прочитал Паронджанова и в голове представляет ДРАКОН-схему, когда такое пишет? Схема с разорванным IF'ом: Код: LOOP Условие A надо поставить перед циклом и в конце его:IF A THEN EXIT END; Step; IF B THEN OneShotCode; EXIT ELSIF C THEN EXIT END; END; Код: IF ~A THEN Далее видим, что LOOP оказался обычным REPEAT..UNTIL'ом:LOOP Step; IF B THEN OneShotCode; EXIT ELSIF C OR A THEN EXIT END END; END; Код: IF ~A THEN Можно записать и как WHILE:REPEAT Step; UNTIL B OR C OR A; IF B THEN OneShotCode; END; END; Код: IF ~A THEN
Step; WHILE ~B & ~(C OR A) DO Step; END; IF B THEN OneShotCode; END; END; |
Страница 1 из 5 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |