входном потоке до первого печатаемого символа. Этот символ затем тоже считывается и С конкретизируется его ASCII-кодом.
В качестве примера использования предикатов, переносящих одиночные символы, давайте рассмотрим процедуру сжатие
, выполняющую следующую работу: считывание из входного потока произвольного предложения и вывод его же, но в форматированном виде — все группы идущих подряд пробелов заменены на одиночные пробелы. Для простоты будем считать, что все предложения входного потока, обрабатываемые процедурой сжатие
, оканчиваются точками, а слова в них отделены одно от другого одним или несколькими пробелами, и только ими. Тогда следующее предложение будет допустимым:
Робот пытался налить вина из бутылки.
Цель сжатие
выведет его в таком виде:
Робот пытался налить вина из бутылки.
Процедура сжатие
будет иметь такую же структуру, как и процедуры обработки файлов из предыдущего раздела. Сначала она прочтет первый символ, выведет его, а затем завершит обработку, в зависимости от того, каким был этот символ. Есть три альтернативы, которые соответствуют следующим случаям: символ является точкой, пробелом или буквой. Взаимное исключение этих трех альтернатив обеспечивается в программе отсечениями:
сжатие :-
get0( С),
put( С).
сделатьостальное( С).
сделатьостальное( 46) :- !.
% 46 -АSСII-код точки, Все сделано
сделатьостальное( 32) :- !,
% 32 - ASCII-код пробела
get( С),
put( С),
сделатьостальное( С).
сделатьостальное( Буква) :-
сжатие.
6.3. Обобщите процедуру сжатие на случай запятых. Все пробелы, стоящие непосредственно перед запятой, нужно убрать, а после каждой запятой нужно поместить единственный пробел.
6.4. Создание и декомпозиция атомов
Часто желательно информацию, считанную как последовательность символов, иметь в программе в виде атома. Для этой цели существует встроенный предикат name
. Он устанавливает взаимосвязь между атомами и их кодировкой в ASCII. Таким образом,
name( A, L)
истинно, если L — список кодов ASCII, кодирующих атом. Например,
name( zx232, [122, 120, 50, 51, 50] )
истинно. Существуют два типичных способа использования name
:
(1) дан атом, разбить его на отдельные символы;
(2) дан список символов, объединить их в один атом.
Примером первого случая применения предиката является программа, которая имеет дело с заказами такси и водителями. Все это представлено в программе атомами
заказ1, заказ2, водитель1, водитель2, такси1, таксилюкс
Предикат
такси( X)
проверяет, относится ли атом X к тем атомам, которые представляют такси:
такси( X) :-
name( X, Хспис),
nаmе( такси, Тспис),
конк( Тспис, _, Хспис).
конк( [], L, L).
конк( [А | L1], L2, [А | L3] ) :-
конк( L1, L2, L3).
Предикаты заказ
и водитель
можно определить аналогично.
Наш следующий пример иллюстрирует применение объединения отдельных символов в один атом. Мы определим предикат
читпредложение( Списслов)
который считает предложение с произвольной формой на естественном языке и конкретизирует Списслов
некоторым внутренним представлением этого предложения. В качестве внутреннего представления, обеспечивающего возможность дальнейшей обработки предложения, естественно избрать следующее: каждое слово входного предложения представляется прологовским атомом, а все предложение представляется списком этих атомов. Например, если входной поток таков:
Мэри было приятно видеть неудачу робота.
то цель читпредложение( Предложение)
вызовет конкретизацию
Предложение=['Мэри', было, приятно, видеть, неудачу, робота]
Для простоты будем считать, что каждое предложение оканчивается точкой и внутри него не используются никакие знаки препинания.
Программа для читпредложение
показана на рис. 6.4. Вначале процедура читает текущий входной символ Симв
, а затем передает его процедуре читостальное
для завершения работы. Процедура читостальное
должна правильно обработать следующие три случая:
(1) Симв
— точка, тогда все сделано.
(2) Симв
— пробел, — игнорировать его и читпредложение
от остального ввода.
(3) Симв
— буква, — сначала считать слово Слово
, которое начинается с Симв
, а затем запустить читпредложение
, чтобы считать оставшуюся часть предложения, породив при этом Списслов
. Общим результатом этого будет список [Слово | Списслов]
.
Процедура, считывающая символы одного слова, такова:
читбуквы( Буква, Буквы, Сделсимв)
Ее три аргумента:
(1) Буква
— текущая буква (уже считанная) читаемого слова.
(2) Буквы
— список букв (начинающийся с буквы Буква
), оставшихся до конца слова.
(3) Следсимв
— входной символ, непосредственно следующий за читаемым словом. Следсимв
не должен быть буквой.
Мы завершим данный пример замечанием о возможном применения процедуры