Разбирал очередной 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.