OberonCore https://forum.oberoncore.ru/ |
|
Убираю LOOP'ы https://forum.oberoncore.ru/viewtopic.php?f=82&t=2547 |
Страница 4 из 5 |
Автор: | Александр Ильин [ Четверг, 21 Апрель, 2011 09:53 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Разбирал очередной LOOP, увидел вот что. Не только выход из LOOP с помощью RETURN, но и выход из FOR c помощью EXIT. Код: d := 0; i := 0; LOOP IF d = LEN (array, 1) THEN RETURN FALSE END; FOR i := 0 TO LEN (array, 0) - 1 DO PrepareForCheck1 (array [d, i]); IF Check1 (array [d, i]) THEN EXIT END; PrepareForCheck2 (array [d, i]); IF Check2 (array [d, i]) THEN EXIT END; END; (* for i *) INC (d); END; (* loop *) HandleSuccess (); RETURN TRUE Первым делом объединил процедуры PrepareForCheckN с CheckN, чтобы можно было целиком поставить в IF (побочных эффектов у них не было). Код: d := 0; i := 0; LOOP IF d = LEN (array, 1) THEN RETURN FALSE END; FOR i := 0 TO LEN (array, 0) - 1 DO IF PrepareAndCheck1 (array [d, i]) THEN EXIT END; IF PrepareAndCheck2 (array [d, i]) THEN EXIT END; END; (* for i *) INC (d); END; (* loop *) HandleSuccess (); RETURN TRUE Уже видно, что внутри FOR условия можно объединить с помощью OR, а сам FOR при этом легко превращается в обычный поисковый WHILE. По сути EXIT из FOR - это успешное завершение поиска, которое надо сигнализировать за пределы LOOP. Заводим для этого переменную res: BOOLEAN: Код: res := FALSE; d := 0; WHILE (d < LEN (array, 1)) & ~res DO i := 0; WHILE (i < LEN (array, 0)) & ~res DO res := PrepareAndCheck1 (array [d, i]) OR PrepareAndCheck2 (array [d, i]); INC (i); END; (* while i *) INC (d); END; (* while d *) IF res THEN HandleSuccess (); END; RETURN res Значения i и d не используются в HandleSuccess. Если бы использовались, то надо было бы их уменьшить на 1 при успешном завершении поиска. Итого, устранены три преждевременных выхода из циклов, добавлена одна локальная переменная, исходник уложился в понятный шаблон и стал короче на 6 строк (правда, пришлось написать вспомогательную процедуру, но она пригодилась ещё раз для усмирения аналогичного LOOP'а в том же модуле). Кстати, сравните приведённый выше код вот с этим: Код: res := FALSE; d := 0; WHILE (d < LEN (array, 1)) & ~res DO i := 0; WHILE (i < LEN (array, 0)) & ~(PrepareAndCheck1 (array [d, i]) OR PrepareAndCheck2 (array [d, i])) DO INC (i); END; (* while i *) res := ~(i < LEN (array, 0)); INC (d); END; (* while d *) IF res THEN HandleSuccess (); END; RETURN res В последнем варианте присвоение res вынесено за цикл, а искомое условие записано в условии цикла. Хотя этот вариант более каноничен, мне всё же препоследний кажется более читабельным из-за явного присвоения res и явного визуального сходства двух WHILE. |
Автор: | Peter Almazov [ Четверг, 21 Апрель, 2011 13:17 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Если я правильно понял, то эти переработки не эквивалентны оригиналу. В нем HandleSuccess () вызывается всегда, там сплошной Success |
Автор: | Евгений Темиргалеев [ Четверг, 21 Апрель, 2011 13:53 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Peter Almazov писал(а): Если я правильно понял, то эти переработки не эквивалентны оригиналу. В нем HandleSuccess () вызывается всегда, там сплошной Success Не всегда --- в теле цикла RETURN
|
Автор: | Илья Ермаков [ Четверг, 21 Апрель, 2011 13:56 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Вот ещё прекрасный пример, за что "прыгунов" "убивать" надо - потом нормальный человек видит в конце процедуры какое-то действие и резонно предполагает, что оно выполняется всегда. |
Автор: | Peter Almazov [ Пятница, 22 Апрель, 2011 12:16 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Вообще, если обе проверки слить в одну, то будет наглядно видно, что это классический поиск в двумерном массиве. Странно, что Info21 не предложил использовать цикл Дейкстры |
Автор: | Александр Ильин [ Понедельник, 25 Апрель, 2011 16:45 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Ужас, летящий на крыльях ночи. Код: PROCEDURE CheckAll (flag: BOOLEAN); Задача - выяснить, в каких отношениях состоят проверки SomeCondition, SomeCheck и переменная fc, после чего упростить код.
VAR done: BOOLEAN; fc: SHORTINT; BEGIN IF SomeCondition () THEN fc := 0; ELSE fc := 2; END; done := FALSE; LOOP IF FirstObject () THEN REPEAT IF fc = 2 THEN IF SomeCheck () THEN DEC (fc) END; ELSIF (fc = 1) & SomeCheck () THEN EXIT ELSIF AccessCheck () THEN done := DoSomething (flag); END; UNTIL done OR ~NextObject (); DEC (fc); ELSE EXIT END; (* if FirstObject *) IF fc < 0 THEN EXIT END; END; (* loop *) END CheckAll; |
Автор: | Евгений Темиргалеев [ Понедельник, 25 Апрель, 2011 17:02 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Александр Ильин писал(а): Код: IF SomeCondition () THEN Задача - выяснить, в каких отношениях состоят проверки SomeCondition, SomeCheck и переменная fc, после чего упростить код.fc := 0; ELSE fc := 2; END; |
Автор: | Valery Solovey [ Понедельник, 25 Апрель, 2011 18:17 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Тут сложно что-то онветить. Непонятно, какие процедуры используют элементы из последовательности (NextObject). fc - это состояние конечного автомата. SomeCondition - это переход с состояния, находящегося на более высоком уровне. SomeCheck - это переход между состояниями на этом уровне. |
Автор: | Александр Ильин [ Понедельник, 25 Апрель, 2011 18:27 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Valery Solovey писал(а): Тут сложно что-то онветить. Непонятно, какие процедуры используют элементы из последовательности (NextObject). FirstObject-NextObject - результаты их работы используются всеми процедурами, кроме SomeCondition. Т.е. SomeCheck, AccessCheck и DoSomething - все, кто находится внутри REPEAT..UNTIL, работают с очередным объектом.
|
Автор: | Valery Solovey [ Понедельник, 25 Апрель, 2011 18:40 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
а FirstObject возвращает к началу последовательности или выдаёт FALSE при повторном обращении? |
Автор: | Александр Ильин [ Понедельник, 25 Апрель, 2011 18:54 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Valery Solovey писал(а): а FirstObject возвращает к началу последовательности или выдаёт FALSE при повторном обращении? Возвращает к началу. FALSE возвращает только если вообще нету объектов для обработки (пустой список).
|
Автор: | Valery Solovey [ Понедельник, 25 Апрель, 2011 20:58 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Стало больше, чем было. Код: PROCEDURE CheckAll (flag: BOOLEAN); VAR done: BOOLEAN; objNotNil, twinsFound : BOOLEAN; BEGIN objNotNil := FirstObject(); IF objNotNil THEN IF SomeCondition() THEN (* fc = 0 *) (*done := AccessCheck() & DoSomething(flag); (* DoSomething не добавляет элементы в последовательность? *) WHILE ~done & NextObject() DO done := AccessCheck() & DoSomething(flag) END*) WHILE ~(AccessCheck() & DoSomething(flag)) & NextObject() DO END ELSE (* fc = 2 *) WHILE objNotNil & ~SomeCheck() DO objNotNil := NextObject() END; IF ~objNotNil THEN (* SomeCheck не нашёл ничего с первого раза - не найдёт и со второго. Поэтому сразу копируем сюда то же, что выполняется для fc = 0 *) objNotNil := FirstObject(); WHILE ~(AccessCheck() & DoSomething(flag)) & NextObject() DO END ELSE (* SomeCheck пытается повторить удачу *) twinsFound := FALSE; done := FALSE; (* цикл ниже не будет работать как исходный пример, если хвост очереди < 2. В исходном примере при хвосте = 1 последовательность завернётся на начало, и SomeCheck снова найдёт тот же объект, что и на предыдущем проходе по последовательности. Так и надо? *) WHILE ~twinsFound & ~done & NextObject() DO twinsFound := SomeCheck(); (*IF ~twinsFound & AccessCheck() THEN done := DoSomething(flag) END;*) done := ~twinsFound & AccessCheck() & DoSomething(flag) END END END END END CheckAll; P.S. Не проверял. |
Автор: | Александр Ильин [ Воскресенье, 01 Май, 2011 06:40 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Valery Solovey писал(а): Стало больше, чем было. Понятно, что станет больше. Это нормально. Здесь проблема как раз в чрезмерной оптимизации. По-хорошему, к такому коду надо комментарий на полстраницы, а тут ни строчки не было.DoSomething ничего в последовательность не добавляет. |
Автор: | Роман М. [ Четверг, 05 Май, 2011 09:48 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Полезно было бы привести теорию оптимальности циклов на графах переходов состояний и показывать на них что излишне и почему. |
Автор: | Valery Solovey [ Четверг, 05 Май, 2011 12:47 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Думаю, здесь цикл завёрнут не на состояния. Там, где цикл можно привязать к состояниям, обычно по-другому делать будет менее рационально. Здесь цикл завёрнут на вызов NextObject: вместо трёх идущих друг за другом действий, каждое из которых обращается к последовательности (выполняет независимый вызов следующего объекта), было объявлено только одно место вызова NextObject, а всё остальное построили вокруг этой операции. То ли решили таким образом соптимизировать что-то, то ли боялись, что при написании кода забудут своевременно добавить вызов процедуры. |
Автор: | Александр Ильин [ Суббота, 02 Февраль, 2019 03:22 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Перечитывал ветку, заметил в этом посте, что финальный вариант кода можно ещё немного сократить. Для начала напомню, с чего всё началось. Код: LOOP ok := Proc1 (); IF ~ok THEN EXIT END; SomeCode (); ok := Proc2 (); IF ok THEN EXIT END; END; После моих сокращений получилось вот так: Код: ok := TRUE; REPEAT IF Proc1 () THEN SomeCode (); ELSE ok := FALSE; END; UNTIL ~ok OR Proc2 (); А можно было ещё чуть проще. Убираем присвоения констант и ветку ELSE: Код: REPEAT
ok := Proc1 (); IF ok THEN SomeCode (); END; UNTIL ~ok OR Proc2 (); |
Автор: | Comdiv [ Суббота, 02 Февраль, 2019 13:59 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Код: ok := FALSE;
WHILE ~ok & Proc1() DO SomeCode (); ok := Proc2 () END |
Автор: | Peter Almazov [ Суббота, 02 Февраль, 2019 20:35 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Хорошие примеры бестолковых попыток сложить мозаику. Выносить Proc() в условие цикла - это "5". Теперь попробуйте объяснить кому-нибудь, что делает этот цикл. Осмысленный вариант: Код: ok := Proc1();
WHILE ok DO SomeCode (); ok := ~Proc2 () & Proc1(); END |
Автор: | Comdiv [ Суббота, 02 Февраль, 2019 22:07 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
"Осмысленный" вариант меняет значение переменной ok, которая по условию должно совпадать с исходным вариантом. Добавьте ещё одну переменную. |
Автор: | Peter Almazov [ Суббота, 02 Февраль, 2019 22:37 ] |
Заголовок сообщения: | Re: Убираю LOOP'ы |
Формально вы правы, я не лез так глубоко, где было это требование. Но оно само по себе является таким же бредом, как и сами представленные здесь потуги. Тут надо в консерватории править. |
Страница 4 из 5 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |