Программирование на языке Пролог | страница 83




рр(Х,I):- not(список(Х)), tab(I), write(X), nl.

pp([H|T],I):- J is I+3, pp(H,J), ppx(T,J), nl.

/*ppx как и ранее */

список([]) список([_|_]).


Нам потребовалось определить соответствующий предикат список таким образом, что целевое утверждение список(Х) является согласованным, если X – список. Первый факт определения этого предиката указывает, что пустой список является списком. Второй факт указывает, что структура, имеющая голову и хвост, является списком. Строго говоря, следовало бы проверить, что хвост структуры также является списком, но мы опустили здесь эту проверку.

Давайте вернемся к фактам, представляющим предикат событие, который мы обсуждали в начале этой главы. Если есть одно из кратких содержаний событий, представленное в виде списка атомов, то можно использовать предикат write, чтобы напечатать каждый атом, вставляя пробел между атомами. Рассмотрим предикат phh для печати краткого содержания событий:


phh([]):- nl.

phh([H|T]):- write(H), tab(l), phh(T).


Так, при следующем запросе было бы напечатано каждое событие, в содержании которого встречается «Англия»:


?- событие(_,L), принадлежит('Англия',L), phh(L).


Обратим внимание на использование механизма возврата для поиска в базе данных. Каждый раз, когда для целевого утверждения принадлежит не находится сопоставление, делается попытка найти новое сопоставление для целевого утверждения событие. В результате в поисках событий, в которых упоминается атом «Англия», будет целиком просмотрена сверху вниз вся база данных.

Предикат write печатает термы с некоторым «пониманием» того, что он делает, так как он учитывает, какие объявления операторов были сделаны. Например, если мы объявили некоторый атом как инфиксный оператор, то терм, имеющий этот атом в качестве функтора структуры с двумя аргументами, будет напечатан таким образом, что атом окажется между аргументами. Существует еще один предикат, который выполняет те же действия, что и write, за тем исключением, что он игнорирует все сделанные объявления операторов. Этот предикат называется display. Различие между write и display иллюстрирует следующий пример:


?- write(a+b*c*c),nl, display(a+b*c*c).

a+b*c*c

+(a,*(*(b,c),c))

да


Обратим внимание на то, что предикат display обработал атомы + и * – точно так же, как и любые другие атомы, которые он печатает в этом терме. Как правило, нежелательно, чтобы печатаемые структуры выглядели подобным образом, так как наличие операторов обычно делает более понятными при чтении как вводимые, так и выводимые программой данные. Однако иногда, когда мы не совсем уверены в том, что знаем, каков приоритет операторов, использование предиката