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