Чтение онлайн

на главную - закладки

Жанры

Программирование на языке пролог
Шрифт:

При печати списков полезно печатать элементы списка таким образом, чтобы получаемый результат можно было легко понять. Списки, которые содержат другие «вложенные» списки, читать особенно трудно, тем более когда внутри них содержатся структуры. Определим предикат рр( pretty print– «хорошая печать») так, что целевое утверждение рр(Х, Y)печатает в удобном виде список, присвоенный в качестве значения переменной X. Смысл второго аргумента предиката рр будет объяснен позднее. Каждый автор программы, реализующей хорошую печать, имеет свой собственный стиль представления списков. Мы воспользуемся методом, при котором элементы списка печатаются в колонку. Если элемент сам является списком, то его элементы печатаются в колонке, которая смещена вправо по отношению к основной колонке. Такая форма представления по существу совпадает с рассмотренным в гл. 3 способом изображения списков. Например, список [1,2,3] «хорошо» печатается в следующем виде:

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

рр(Х,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обработал атомы + и * – точно так же, как и любые другие атомы, которые он печатает в этом терме. Как правило, нежелательно, чтобы печатаемые структуры выглядели подобным образом, так как наличие операторов обычно делает более понятными при чтении как вводимые, так и выводимые программой данные. Однако иногда, когда мы не совсем уверены в том, что знаем, каков приоритет операторов, использование предиката displayможет оказаться очень полезным.

5.1.2. Ввод термов

Предикат readчитает следующий терм, набираемый пользователем на клавиатуре терминала. После вводимого терма должны следовать точка '.' и непечатаемая литера, такая как пробел или

RETURN
. Если переменная Xне конкретизирована, то целевое утверждение read(X)приведет к вводу следующего терма и этот терм будет присвоен в качестве значения переменной X, Как и другие предикаты ввода-вывода, с которыми мы уже сталкивались, предикат readвыполняется лишь один раз. Если в момент рассмотрения целевого утверждения read(X)его аргумент конкретизирован, то попытка доказать согласованность этого целевого утверждения с базой данных вызовет чтение следующего терма и попытку сопоставления его с аргументом, заданным в read.Согласованность цели с базой данных зависит от результата этого сопоставления.

Поделиться:
Популярные книги

Матабар IV

Клеванский Кирилл Сергеевич
4. Матабар
Фантастика:
фэнтези
5.00
рейтинг книги
Матабар IV

География растений

Гумбольдт Александр
Классики естествознания
Научно-образовательная:
ботаника
7.50
рейтинг книги
География растений

Бандит

Щепетнов Евгений Владимирович
1. Петр Синельников
Фантастика:
фэнтези
7.92
рейтинг книги
Бандит

Третий

INDIGO
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий

Жизнь, которой не было

Денис Палимов
1. Жизнь, которой не было
Фантастика:
городское фэнтези
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Жизнь, которой не было

Орден Архитекторов 9

Винокуров Юрий
Фантастика:
попаданцы
фэнтези
5.00
рейтинг книги
Орден Архитекторов 9

Неучтенный элемент. Том 11

NikL
11. Антимаг. Вне системы
Фантастика:
фэнтези
5.00
рейтинг книги
Неучтенный элемент. Том 11

Дважды одаренный. Том IV

Тарс Элиан
4. Дважды одаренный
Фантастика:
городское фэнтези
альтернативная история
аниме
7.00
рейтинг книги
Дважды одаренный. Том IV

Монстр из прошлого тысячелетия

Еслер Андрей
5. Соприкосновение миров
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Монстр из прошлого тысячелетия

Пушкарь. Пенталогия

Корчевский Юрий Григорьевич
Фантастика:
альтернативная история
8.11
рейтинг книги
Пушкарь. Пенталогия

Газлайтер. Том 26

Володин Григорий Григорьевич
26. История Телепата
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Газлайтер. Том 26

Неучтенный элемент. Том 7

NikL
7. Антимаг. Вне системы
Фантастика:
фэнтези
5.00
рейтинг книги
Неучтенный элемент. Том 7

Бастард Императора. Том 2

Орлов Андрей Юрьевич
2. Бастард Императора
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бастард Императора. Том 2

Травник

Назимов Константин Геннадьевич
1. Травник
Фантастика:
фэнтези
5.00
рейтинг книги
Травник