• «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» (аварийное завершение): Эта команда вызывает прекращение выполнения всех ваших текущих программ, и вы «проваливаетесь» в Пролог-интерпретатор, который готов к вашему новому вопросу.
• «halt» (стоп): Эта команда вызывает полный выход из Пролога. Она может потребоваться вам, когда вы обнаружите ошибку и захотите для ее исправления отредактировать файл с той программой, где находится ошибка.
В заключение хочется обратить внимание на три вопроса, ответы на которые следует продумать, прежде чем приступать к трассировке выполнения программы:
1. За какими целями вы собираетесь следить? Если вы хотите следить за всем (задав полную трассировку с помощью предиката trace), то вы можете захлебнуться тем потоком информации, который будет поступать на ваш терминал. С другой стороны, если прослеживать только то, что происходит с небольшим числом предикатов (расставляя контрольные точки с помощью предиката spy), то можно пропустить момент, когда программа начинает работать неверно. Вероятно, лучшим решением является компромисс между аккуратным использованием контрольных точек, позволяющих сузить район поиска, и полной трассировкой на заключительном этапе, что позволяет точно обнаружить место ошибки.
2. Какой уровень управления выполнением программы вы намерены осуществить через терминал? Если задать все типы событий как неуправляемые, то вы не сможете оказать никакого влияния на ход выполнения программы, которая быстро проскочит через место ошибки прежде чем вы сможете это заметить, а тем более – внимательно рассмотреть. С другой стороны, если вы зададите все события как управляемые, то вам придется постоянно подталкивать программу, сообщая ей, что нужно продолжить выполнение при каждом новом событии.
3. Намерены ли вы задать специальные средства вывода информации о прослеживаемых целях? Это может оказаться полезным в тех случаях, когда некоторые из целей содержат в качестве аргументов чрезмерно большие структуры, которые не представляют особого, интереса, и только отвлекают внимание от действительно интересных аргументов. В этом случае для подавления выдачи ненужной информации можно воспользоваться возможностями предиката portray.