• Удаление всех контрольных точек. Это имеет тот же эффект, что и вызов цели nodebug (см. разд. 6.13).
• Отключение полной трассировки. Это имеет тот же эффект, что и вызов цели notrace (см. разд. 6.13).
• Включение полной трассировки. Это имеет тот же эффект, что и вызов цели trace (см. разд. 6.13).
При задании любой из этих команд ваша программа продолжит затем выполнение в указанном режиме до тех пор, пока не дойдет до цели, которую вы намеревались прослеживать. В некоторых версиях Пролога могут быть предусмотрены более тонкие средства управления трассировкой. Эти средства помогут вам быстро пройти через те участки выполнения программы, которые не представляют интереса с тем, чтобы сосредоточиться на участках, где, вероятно, имеются ошибки. Здесь возможны следующие команды:
• «creep» (ползти): Продолжить выполнение программы с полной трассировкой до тех пор, пока не поступит новое указание (при наступлении следующего управляемого события).
• «skip» (пропустить): Продолжить выполнение программы без выдачи какой-бы то ни было трассировочной информации до тех пор, пока не наступит какое-либо событие, относящееся к текущей цели.
• «leap» (перескочить); Продолжить выполнение программы без выдачи трассировочной информации до тех пор, пока либо не будет достигнута контрольная точка, либо не наступит событие, относящееся к текущей цели.
Первая из этих команд соответствует случаю, когда вы хотите, начиная с данного момента, тщательно проследить за ходом выполнения программы. Вторая команда соответствует случаю, когда вас не интересует ход согласования какой-либо цели, а нужно побыстрее перейти к тому, что происходит дальше. Третья команда относится к случаю, когда в ходе согласования некоторой цели выполняется большой объем не интересующей вас деятельности, но где-то в середине возникает интересующая вас цель (имеющая контрольную точку). Поэтому вам желательно пропускать все до тех пор, пока не будет достигнута нужная контрольная точка или (если программа ошибочна) пока текущая цель не окажется согласованной или несогласованной не достигнув контрольной точки. Ниже приводится пример использования команд «creep» и «skip». Предположим, что в простой программе сортировки, приведенной в разд. 7.7, есть ошибка, но при этом мы уверены, что наша программа порождения перестановок работает правильно. Если вы помните, определение программы наивсорт начинается так:
наивсорт(Х,Y):- перестановка(Х,Y), отсортировано(Y),!.
Чтобы избежать необходимости просматривать массу детальных сведений о том, как работает программа перестановка, можно воспользоваться командой «skip» и получить трассировку, которая начинается так:
CALL наивсорт([3,6,2,9,20],_45)? creep
CALL перестановка([3,6,2,9,20],_45)? skip
EXIT перестановка([3,6,2,9,20],[3,6,2,9,20])? creep
CALL упорядочено(ЕЗ,6,2,9,20])? creep
CALL упорядочено(0,[3,6,2,9,20])? creep
CALL 0‹3?
. . .
Здесь рассматриваются команды, которые позволяют изменять порядок работы программы. С их помощью можно повторить некоторые фрагменты, которые желательно изучить более подробно, обойти случаи про которые известно, что они не относятся к делу и наоборот, заставить программу рассмотреть случаи, которые иначе она могла бы и не обнаружить. Все это способно значительно ускорить отладку, поскольку позволяет подвергнуть многократной проверке особо сложные части программы не повторяя заново весь ее запуск с самого начала.
• «retry» (повторить): Если вы задали команду «retry» после какого-либо события для некоторой цели, то Пролог вернется к тому месту, где он первоначально осуществил ВЫЗОВ (событие CALL) этой цели. Все будет в точности так же, как и в момент первоначального появления этой цели (кроме каких-либо добавлений к базе данных, которые могли быть сделаны). Это означает, что вы можете еще раз проследить за тем, что происходит при согласовании данной цели. На практике обычно сочетают использование команд «retry» и «skip». Если вы сомневаетесь в том, что ошибка возникает при согласовании некоторой цели, вы можете сперва пропустить (с помощью команды «skip») трассировку процесса ее согласования. Это означает, что вы не намерены пробираться через массу трассировочных данных, относящихся к цели, процесс согласования которой выполняется совершенно правильно. Если же возникла ошибка, и цель либо не согласуется с базой данных, либо дает неверный результат, то у вас сохраняется возможность после всего этого (с помощью команды «retry») вернуться назад и проследить за всем более внимательно.
• «or» (или): Эта команда, в точности как ';', означает просьбу о выборе альтернативного решения некоторого вопроса. Если вы находитесь в точке ВЫХОДа из цели (событие EXIT), вы также можете попросить о выборе альтернативы. Таким образом, если известно, что первый найденный ответ не позволяет успешно завершить остальную часть программы, можно тут же попросить о поиске другого решения. Это означает, что вы сможете быстрее добраться до той части программы, где содержится ошибка. Без такого режима вам пришлось бы «караулить» возможную неудачу процесса согласования после того, как была найдена первая альтернатива.
• «fail» (неудача): Эта команда в основном используется при наступлении события CALL. Если вы знаете, что данная цель в конце концов окажется несогласованной с базой данных, и что эта цель для вас не представляет интереса, то вы можете тут же принудительно завершить процесс согласования неудачно, задав эту команду.
Ниже приводится пример использования различных рассмотренных команд при изменении порядка согласования одного вопроса:
?- принадлежит(Х,[а,b,с]), принадлежит(Х,[b,d,е]).
CALL принадлежит(_ 44,[a, b,с])? creep
EXIT принадлежит(a, [а,b,с])? or
REDO принадлежит(a, [а,b,с])? creep
CALL принадлежит(_44,[b,с])? fail
FAIL принадлежит(_44,[b,с])? creep
FAIL принадлежит(_44,[a,b,с])? retry
CALL принадлежит(_44,[а,b,с])? creep
EXIT принадлежит(а,[а,b,с])? creep
CALL принадлежит(а,[d,с,е])? fail
FAIL принадлежит(a,[d,c,e])? creep
REDO принадлежит(а,[а,b,с])? creep
CALL принадлежит(_44,[b,с])? creep
EXIT принадлежит(b,[b,с])? or
REDO принадлежит(b,[b,с])? creep
CALL принадлежит(_ 44,[с])? fail
FAIL принадлежит(_44,[с])? retry
CALL принадлежит(_44,[с])? creep E
XIT принадлежит(с,[с])? creep
EXIT принадлежит(с,[b,c])? creep
EXIT принадлежит(c,[a,b,с])? creep
CALL принадлежит(c,[d,c,e])? creep
CALL принадлежит(c,[c,e])? creep
EXIT принадлежит(c,[c,e])? creep
EXIT принадлежит(c,[d,c,e])? or
REDO принадлежит(c,[d,c,e])? creep
REDO принадлежит(c,[c,e])? creep
CALL принадлежит(c,[e])? creep
CALL принадлежит(c,[])? creep
FAIL принадлежит(c,[])? creep
FAIL принадлежит(c,[е])? creep
FAIL принадлежит(c,[с,е])? retry
CALL принадлежит(c,[с,e])? creep
EXIT принадлежит(c,[c,e])? creep
EXIT принадлежит(с,[d,с,е])? creep
Рассмотрим другие возможные команды, которые могут быть доступны вам при наступлении управляемого события;
• «break» (пауза): Эта команда вызывает приостановку выполнения текущей программы, причем вам предоставляется новая копия Пролог-интерпретатора, Вы можете воспользоваться этим для задания вопросов относящихся к утверждениям, которыми вы располагаете, для расстановки контрольных точек или для чего-нибудь еще. Когда вы выйдете из этой копии интерпретатора (путем ввода литеры, являющейся признаком конца файла), то выполнение вашей прежней программы будет продолжено.
• «abort» (аварийное завершение): Эта команда вызывает прекращение выполнения всех ваших текущих программ, и вы «проваливаетесь» в Пролог-интерпретатор, который готов к вашему новому вопросу.