обр([],[]).
oбp([H|T],L):- oбp(T,Z), присоединить(Z,[H],L).
присоединить([],X,Х).
присоединить([А|В],С,[А|D]):- присоединить(В,С,D).
Пусть мы задали исходный вопрос:
?- oбp([a,b,c,d],X). (A)
Тогда, вследствие второго утверждения, возникают две подцели, каждая из которых в качестве своего непосредственного предшественника имеет цель, составляющую содержание исходного вопроса. Вот эти подцели:
oбp([b,c,d],Z) (B)
присоединить(Z,[a],X) (C)
Поскольку второе утверждение будет снова использовано при согласовании (B), снова возникают две подцели:
oбp([c,d],Z1) (D)
присоединить(Z1,[a],Z) (E)
Их предшественниками являются цели (A) и (B). Заметим, что цель (C) не является их предшественником, поскольку от них непосредственно зависит только согласованность (B) , от которой, в свою очередь, зависит согласованность (А). Цели (D) и (E) никак не влияют на согласованность (C) . Когда процесс согласования исходного вопроса заходит уже достаточно далеко, возникает цель вида:
присоединить([с],[b],Y)
На этом этапе текущая цель и ее предшественники могут быть представлены в следующем виде:
oбp([a,b,c,d],_46) (цель A)
oбp([b,c,d],[d|_50]) (цель B)
присоединить([d,с],[b],[d|_51])
присоединить([с],[b],_52)
Прежде чем читать дальше, вам следует убедиться в том, что вы понимаете, почему это предшественники данной цели, а также почему у нее нет никаких других предшественников. С приведенным здесь изображением предшественников связана одна особенность, которая может проявиться и в вашей Пролог-системе. Существуют два способа выдачи информации о предшественнике на печать – при первом способе информация соответствует состоянию предшественника при первой попытке согласовать его, при втором – текущему состоянию, с теми значениями переменных, которые они получили в результате конкретизации. Здесь у нас принят второй способ. Когда выполнение впервые дошло до цели (B), второй аргумент предиката обрне был конкретизирован. Тем не менее, в списке предшественников этот аргумент показан как имеющий значение. Это объясняется тем, что теперь переменная, которая задана в этой позиции, оказалась конкретизированной, а именно, теперь мы выяснили, что для [b, с, d]первым элементом обращенного списка является d.
Глядя на предшественников текущей цели можно получить ясное представление о том, что происходит с программой и почему она делает то, что наблюдается. Одной из команд, которые пользователю разрешается вводить при наступлении управляемого события для некоторой цели может быть выдача сведений о каких-либо из ее предшественников. Таким образом, если вы чувствуете, что ваша программа тратит где-то много времени и подозреваете, что это может быть результатом зацикливания, то верная стратегия состоит в том, чтобы прервать выполнение, включить полную трассировку, а затем посмотреть на предшественников, чтобы понять, где вы находитесь.
Изменение уровня трассировки
Другой набор команд, которыми можно воспользоваться при наступлении управляемого события, связан с изменением желаемого объема трассировки. Некоторые из более грубых управляющих воздействий состоят в следующем.
• Удаление всех контрольных точек. Это имеет тот же эффект, что и вызов цели nodebug(см. разд. 6.13).
• Отключение полной трассировки. Это имеет тот же эффект, что и вызов цели notrace(см. разд. 6.13).
• Включение полной трассировки. Это имеет тот же эффект, что и вызов цели trace(см. разд. 6.13).
При задании любой из этих команд ваша программа продолжит затем выполнение в указанном режиме до тех пор, пока не дойдет до цели, которую вы намеревались прослеживать. В некоторых версиях Пролога могут быть предусмотрены более тонкие средства управления трассировкой. Эти средства помогут вам быстро пройти через те участки выполнения программы, которые не представляют интереса с тем, чтобы сосредоточиться на участках, где, вероятно, имеются ошибки. Здесь возможны следующие команды:
• «creep» (ползти): Продолжить выполнение программы с полной трассировкой до тех пор, пока не поступит новое указание (при наступлении следующего управляемого события).
• «skip» (пропустить): Продолжить выполнение программы без выдачи какой-бы то ни было трассировочной информации до тех пор, пока не наступит какое-либо событие, относящееся к текущей цели.
• «leap» (перескочить); Продолжить выполнение программы без выдачи трассировочной информации до тех пор, пока либо не будет достигнута контрольная точка, либо не наступит событие, относящееся к текущей цели.
Читать дальше