Лекция 6

 

 

 

Встроенные предикаты. Поиск на Прологе.

 

 

Cодержание

6.1 Отрицание как неудача. (not as failure).

6.2 Алгоритм поиска на Прологе.

6.3 Чтение и запись информации с файлов.

6.3.1 Обработка входных потоков.

6.3.2 Обработка выходных потоков.

6.4 Обработка символов.

6.4.1 put(X)

6.4.2 get(X)

6.4.3 get0(X)

6.5 Три предиката ARITY-prologa.

6.1 Отрицание как неудача. (not as failure)

Рассмотрим сначала пример.

Пусть некоторая Мэри любит всех животных.

Это записывается:

likes(mary,X):-annimal(X).

 

 

 

 

Мэри не любит змей:

likes(mary,X):-snake(X),!,fail.


fail - специальная цель, встроенный предикат,
который всегда терпит неудачу.

 

 

Графически предикат изображается:

Можно записать в виде одного правила, используя

дизъюнкцию целей.

likes(mary,X):-snake(X),!,fail;
annimal(X).

 

 

Посмотрим другой пример.

Отношение different(X,Y) будет истина,если X и Y различны. (не сопоставимы).

 

different(X,X):-!,fail.
или
different(X,Y):-X=Y,!,fail.
different(X,Y).

 

 

 

Если 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).
yes
?-p(X),g(X).
no.

 

 

 

6.2 Алгоритм поиска на Прологе.

( Логический подход к задаче о фермере, волке, козе и капусте.)

Задача заключается в следующем:

Фермер ( 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 */
move(state(X,W,X,C),state(Y,W,Y,C)):-opposite(X,Y). /* FARMER + GOAT */
move(state(X,W,G,X),state(Y,W,G,Y)):-opposite(X,Y). /*FARMER + CABBIDGE*/
move(state(X,W,G,C),state(Y,W,G,C)):-opposite(X,Y). /* ONLY FARMER */

 

 

 

Теперь можно определить предикат opposite, который определяет другую сторону.

opposite(east,west).
opposite(west,east).

Предикат unsafe определен для проверки двух опасных состояний:

unsafe( state(F,X,X,_) ):- opposite(F,X).
/* The wolf eats the goat */

 

 

 

 

unsafe( state(F,_,X,X) ):- opposite(F,X).
/* The goat eats the cabbage */

 

 

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|_]).
member(X,[_|L]):-member(X,L).

   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( _ ).

 

 

 

Сама программа намного короче программы на лиспе.

6.3 Чтение и запись информации с файлов.

При вводе и выводе информации в прологе используется понятие потоков.
Файлы для чтения - это входные потоки.
Файлы для записи - это выходные потоки.

Для пользователя определены два потока:

информация вводимая с клавиатуры - входной поток.

 

 

 

информация выводимая на монитор - выходной поток.

 

 

Эти потоки являются псевдофайлами с именем user.

В каждый момент времени для пролога активны два файла:

для ввода - текущий входной поток.

 

 

 

для вывода - текущий выходной поток.

 

 

По умолчанию эти потоки - пользовательский терминал user.

6.3.1 Обработка входных потоков.

Входные потоки пролог "видит".

Поэтому определены следующие предикаты:

  • see(F) - открывает файл F, например 'a.dat' и он становится текущим входным потоком.
  • seeing(F) - связывает F с именем файла, являющегося текущим входным потоком.
  • seen - закрывает текущий входной поток и связывает его с user.

 

 

 

Иллюстрация SEE

 

 

 

 

 

Иллюстрация SEEN

 

 

 

 

Примеры:

 

p1:-see('a.dat'),read(X),write(X),seen.

p2:-see('a.dat'),seeing(F),write(F),seen,
read(A),write(A).

 

 

 

6.3.2 Обработка выходных потоков.

В выходные потоки пролог "говорит".

  • tell(F) - открывает файл F как текущий выходной поток. Если файла нет, то создает его.
  • telling(F)- связывает F с именем файла, являющегося текущим выходным потоком.
  • told - закрывает файл, являющиийся текущим выходным потоком. Текущим выходным потоком становится user.

 

 

Пример:

p3:- tell('a.dat'),write(a),told,write(a).

 

6.4 Обработка символов.

Пролог имеет несколько предикатов для обработки символов.

6.4.1 put(X)

Символы записываются в текущий выходной поток при помощи предиката put(C), где
C - символ, который нужно вывести, представленный в кодировке ASCII ( число от 0 до 127).

Иллюстрация PUT

 

 

 

 

Пример:

p4:-put(65),put(66),put(67).

?-p4.
ABC

 

 

 

6.4.2 get(X)

Печатный символ (код по ASCII больше 31) читается предикатом get(X). Аргумент X принимает числовое значение. Непечатный символ игнорируется.

 

 

6.4.3 get0(X)

Читает любой (печатный или нет) символ.

 

 

6.5 Три предиката ARITY-prologa.

Два предиката ARITY-prologa для работы с кусором.

  • tget(Y,X) Выдает текущие координаты курсора.
  • tmove(Y,X) Перемещает курсор в заданные позиции.

 

 

 

Иллюстрация TMOVE

 

 

 

 

 

Пример:

p5:-write('+++++'),tget(Y,X),X1 is X-4,tmove(Y,X1),
write('***').

 

?-p5.
+***+

 

 

 

 

Иллюстрация примера

 

 

 

 

Еще один полезный предикат: cls.
Он, как можно догадаться, очищает экран.


(c) M.N.Morozov, 1999.

информация

проекты

публикации

материалы

друзья

студенты

 

связи

 

 

Hosted by uCoz