|
Лекция
6 |
|
|
|
Встроенные предикаты. Поиск на
Прологе. |
|
|
6.1 Отрицание как неудача.
(not as failure).
6.2 Алгоритм поиска на
Прологе.
6.3 Чтение и запись
информации с файлов.
6.3.1 Обработка входных
потоков.
6.3.2 Обработка выходных
потоков.
6.5 Три предиката
ARITY-prologa.
Рассмотрим сначала
пример.
|
Пусть некоторая Мэри любит всех животных. Это записывается: likes(mary,X):-annimal(X). |
|
|
|
|
Мэри не любит змей: likes(mary,X):-snake(X),!,fail.
|
|
|
|
Графически предикат изображается:
|
Можно записать в виде одного правила, используя likes(mary,X):-snake(X),!,fail; |
|
|
Посмотрим другой пример.
Отношение different(X,Y) будет
истина,если X и Y различны. (не
сопоставимы).
|
different(X,X):-!,fail. |
|
|
|
|
Если X и Y сопоставимы, то цель different терпит
неудачу.
Иначе X и Y различны, и цель different успешна.
Или в одном предложении
different(X,Y):-X=Y,!,fail;true.
Здесь true - встроенный педикат, который всегда истина.
И в том и другом случае более удобно
указывать, что отношение истинно, если цель ложна.
Для этой цели используется предикат not.
not(Goal). -истина, если Goal -ложь, и наоборот not(Goal)
ложно, если Goal успешна.
Это можно записать:
not(Goal):-Goal,!,fail;true.
Запись аналогична сделанным, поэтому наши примеры можно переписать:
likes(mary,X):-annimal(X),not(snake(X)).
или
different(X,Y):-not(X=Y).
!
|
Использование not требует осторожности, т.к.
определяется через |
|
|
Рассмотрим пример:
r(a).
g(b).
p(X):-not(r(X)).
|
?-g(X),p(X). |
|
|
|
|
( Логический подход
к задаче о фермере, волке, козе и капусте.)
Задача заключается в
следующем:
Фермер ( Farmer ), волк ( Wolf
), козел ( Goat ) и капуста ( Cabbidge ) находятся на одном берегу. Надо
перебраться на другой берег на лодке. Лодка перевозит только двоих. Нельзя
оставлять на одном берегу козу и капусту,козу и волка.
|
!
|
Главная проблема в формировании
алгоритма - найти эффективное представление структурой данных Лиспа
информации о задаче. |
|
|
|
|
|
Процес перевозки может
быть представлен последовательностью состояний. Состояние
представляется отношением state c 4 аргументами, каждый из
которых отражает размещение обьектов F,W,G,S :
|
|||
Farmer |
Wolf |
Goat |
Cabbidge |
state(e, w, e, w) - F,G in east side (e - east);
F W G C W,C in west side (w - west).
Оставшаяся программа
основывается на этих предикатах. В частности,они используются для реализации четырех возможных действий фермера, выраженных в перевозе
фермера через реку:
Предикат
opposite ( определена позже ) определяет новое размещение объектов,
которые пересекли реку.
|
move(state(X,X,G,C),state(Y,Y,G,C)):-opposite(X,Y). /*
FARMER + WOLF */ |
|
|
|
|
Теперь можно определить предикат opposite,
который определяет другую сторону.
opposite(east,west).
opposite(west,east).
Предикат unsafe определен для
проверки двух опасных состояний:
|
unsafe( state(F,X,X,_) ):- opposite(F,X). |
|
|
|
|
unsafe( state(F,_,X,X) ):- opposite(F,X). |
|
|
|
path теперь определяется:
|
path(S,G,L,L1):- move(S,S1), not( unsafe(S1) ), not( member(S1,L) ), path( S1,G,[S1|L],L1),!. path(G,G,T,T):-!. /* The final state is reached */ |
|
|
|
|
Для решения можно использовать:
|
go:- go(state(east,east,east,east),state(west,west,west,west)). go(S,G):- path(S,G,[S],L), nl,write('A solution is:'),nl, write_path(L), fail. go(_,_). |
|
|
|
|
Для организации удобной формы вывода
использованы следующие процедуры:
|
member(X,[X|_]). write_move( state(X,W,G,C), state(Y,W,G,C) ) :-!, write('The farmer crosses the river from '), write(X), write(' to '), write(Y),nl. write_move( state(X,X,G,C), state(Y,Y,G,C) ) :-!, write('The farmer takes the Wolf from '), write(X), write(' of the river to '), write(Y),nl. write_move( state(X,W,X,C), state(Y,W,Y,C) ) :-!, write('The farmer takes the Goat from' ), write(X), write(' of the river to '), write(Y),nl. write_move( state(X,W,G,X), state(Y,W,G,Y) ) :-!, write('The farmer takes the cabbage from '), write(X), write(' of the river to '), write(Y),nl. write_path( [H1,H2|T] ) :- !, write_move(H1,H2),write_path([H2|T]). write_path( _ ). |
|
|
|
|
Сама программа намного короче
программы на лиспе.
При вводе и выводе
информации в прологе используется понятие потоков.
Файлы для чтения - это входные потоки.
Файлы для записи - это выходные потоки.
Для пользователя определены два потока:
информация вводимая с клавиатуры - входной поток. |
|
|
|
|
информация выводимая на монитор - выходной поток. |
|
|
Эти потоки являются псевдофайлами с именем user.
В каждый момент времени для пролога
активны два файла:
для ввода - текущий
входной поток. |
|
|
|
|
для вывода - текущий
выходной поток. |
|
|
По умолчанию эти потоки -
пользовательский терминал user.
Входные потоки пролог "видит". Поэтому определены следующие предикаты:
|
|
|
|
Иллюстрация SEE |
|
||
|
|
|
|
Иллюстрация SEEN |
|
||
|
|
|
|
Примеры:
|
p1:-see('a.dat'),read(X),write(X),seen. p2:-see('a.dat'),seeing(F),write(F),seen, |
|
|
|
|
В выходные потоки пролог "говорит".
|
|
|
|
Пример:
p3:- tell('a.dat'),write(a),told,write(a).
Пролог имеет несколько
предикатов для обработки символов.
Символы записываются в
текущий выходной поток при помощи предиката put(C), где
C - символ, который нужно вывести, представленный в кодировке ASCII (
число от 0 до 127).
Иллюстрация PUT |
|
||
|
|
|
|
Пример:
p4:-put(65),put(66),put(67).
|
?-p4. |
|
|
|
|
Печатный символ (код по ASCII больше 31) читается
предикатом get(X). Аргумент X принимает числовое значение.
Непечатный символ игнорируется. |
|
|
|
Читает любой (печатный или нет) символ. |
|
|
|
Два предиката ARITY-prologa для работы с кусором.
|
|
|
|
Иллюстрация TMOVE |
|
||
|
|
|
|
Пример:
p5:-write('+++++'),tget(Y,X),X1 is
X-4,tmove(Y,X1),
write('***').
|
?-p5. |
|
|
|
|
Иллюстрация примера |
|
|
|
|
|
Еще один полезный предикат: cls.
Он, как можно догадаться, очищает экран.
(c) M.N.Morozov, 1999.