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



1

2

3

а список [1,2,[3,4],5,6] печатается как

1

2

   3

   4

5

6

Заметим, что мы решили не печатать квадратные скобки и запятые, разделяющие элементы списка. Если элемент списка является структурой, то он будет обрабатываться точно таким же способом, что и атом. При таком подходе нам не нужно «раскрывать организацию» структур, чтобы «хорошо» напечатать их компоненты. Следующая программа реализует определенный нами способ хорошей печати:


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

pp(X,I):- tab (I), write(X), nl.

ppx([],_).

ppx([H|T],I):- pp(H,I), ppx(T,I).


Теперь видно, что второй аргумент предиката рр выполняет функции счетчика колонок. Целевое утверждение «верхнего уровня» для печати некоторого списка могло бы выглядеть как


… PP(L,0),…


при этом начальное значение счетчика колонок устанавливается равным 0. Первое утверждение предиката рр обрабатывает специальный случай – когда первый аргумент является списком. Если это так, то необходимо установить новую колонку, увеличив счетчик на некоторое число (здесь 3). Затем мы должны отпечатать с помощью рр голову списка, так как она сама может оказаться списком. Далее нужно напечатать все элементы хвоста списка, располагая каждый элемент в той же самой колонке. Это как раз и выполняет предикат ррх. А предикат ррх использует рр, поскольку каждый элемент может быть списком. Второе утверждение предиката рр соответствует случаю, когда нам необходимо напечатать что-либо, не являющееся списком. Мы просто делаем отступ на указанное число позиций, используем предикат write для печати терма и nl для перехода на новую строку. Первое утверждение для рр также заканчивается nl, поскольку печать каждого списка должна завершиться переходом на новую строку.

Отметим, что в предикате рр мы поместили утверждение для обработки особого случая перед утверждением, обрабатывающим выход на граничное условие. Если бы мы поместили второе утверждение перед первым утверждением, то тогда список, являющийся первым аргументом предиката рр, был бы сопоставлен с переменной X в заголовке второго правила. В результате получилось бы, что список был бы просто напечатан как единое целое без удобств и «хорошей» печати. Поэтому мы хотим, чтобы случай, когда аргумент является списком, проверялся первым. Именно поэтому мы выбрали такой порядок утверждений. Второе утверждение используется как правило-ловушка. Другой способ добиться такого же результата состоит в том, чтобы правило, осуществляющее проверку граничного условия, поставить первым и включить в его тело подцель, которая не выполняется, если первый аргумент является списком: