Материал: Методическое пособие по Turbo Prolog (новое)

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Для описания этого предиката в разделе goal программы можно использовать конструкцию:

show :- dogs(X), print_list(X).

Если необходимо установить наличие некоторого элемента в списке, то применяется правило:

find_it( X,[X| _ ]).

find_it( X,[ _ |Y]):- find_it( X,[Y]).

В первом описании происходит сравнение объекта поиска и головы текущего списка. Если это сравнение неуспешно, то происходит откат и попытка повторения со вторым вариантом.

Программа 14

DOMAINS dog_list=symbol*

PREDICATES dogs(dog_list). find_it(symbol,dog_list).

GOAL

find_it(«болонка»,[«лайка», «дог» ]),write(“да”). CLAUSES

find_it(X,[X,_]). find_it(X,[_,Y]):-find_it(X,[Y]).

Первое правило описывает ситуацию, когда искомый элемент Х совпадает с головой списка.

Второе правило используется при неуспехе первого правила и описывает новый вызов первого правила, но уже с усеченным списком, в котором нет первого элемента и т.д. Если в списке нет элементов (пустой список), то второе правило оказывается неуспешным.

Программа не напечатает Yes, поскольку болонки нет в списке собак.

Следующий пример производит подсчет суммы всех элементов списка чисел.

Программа 15

DOMAINS spisok=integer*

PREDICATES summa_sp(spisok,integer)

21

CLAUSES summa_sp([],0).

summa_sp([H|T],S):-summa_sp(T,S1),S= H +S1.

Рассмотрим операцию слияния двух списков.

Пусть L1 и L2 – две переменные, представляющие входные списки. L3 – выходной список, получаемый слиянием L1 и L2.

append([ ],L,L).

append( [N|L1], L2, [N|L3] ):- append(L1, L2, L3).

Первый вариант этого правила выполняется когда первый список пустой, второй работает в остальных случаях.

Рассмотрим использование этого предиката при следующем вызове:

append([1,2,3], [4,5],_).

Здесь первый вариант правила сначала не работает, так как первый список не пустой.

Начинает работать второе правило, так как третий список пустой, к нему не применима операция деления на голову и хвост. Что касается первого списка, то он в процессе рекурсивных вызовов претерпевает деления на голову и хвост, и в конце концов становится пустым (его элементы попадают в стек)

append([ ],[4,5],_).

После этого срабатывает первый вариант правила, и третий список инициализируется вторым:

append([ ],[4,5], [4,5]).

И, наконец, чтобы завершить рекурсивные вызовы, ПРОЛОГ извлекает из стека (в обратном порядке) элементы первого списка и возвращает их, в соответствии с описанием второго варианта правила, в списки 1 и 3:

append([1,2,3], [4,5],[1,2,3,4,5]).

Рассмотрим, как используются списки и механизм рекурсии при решении известной задачи о мужике, волке, козе и капусте.

22

Программа 16

 

DOMAINS

 

LOC = east ; west

/* описание берегов */

STATE = state(LOC,LOC,LOC,LOC)

/* описание положения объектов */

PATH = STATE*

/* список состояний */

PREDICATES

 

go(STATE,STATE)

/* запуск алгоритма */

path(STATE,STATE,PATH,PATH)

/* поиск пути к новому состоянию */

move(STATE,STATE)

/* переход от состояния к состоянию */

opposite(LOC,LOC)

/*описаниепротивоположныхсторон*/

unsafe(STATE)

/* описание опасных состояний */

member(STATE,PATH)

/* было ли такое состояние ? */

write_path(PATH)

/* вывод ответа */

write_move(STATE,STATE)

/* распечатка хода */

GOAL

 

go(state(east,east,east,east),state(west,west,west,west)), write(“solved press any key to continue”),

readchar(_), exit.

CLAUSES go(S,G):-

path(S,G,[S],L), nl,write(“A solution is:”),nl, write_path(L),

fail. go(_,_).

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):- !. /* Конечное состояние найдено, список L копируется в L1*/ move(state(X,X,G,C),state(Y,Y,G,C)):-opposite(X,Y). /* мужик и волк */ move(state(X,W,X,C),state(Y,W,Y,C)):-opposite(X,Y). /* мужик и коза */ move(state(X,W,G,X),state(Y,W,G,Y)):-opposite(X,Y). /* мужик и капуста */ move(state(X,W,G,C),state(Y,W,G,C)):-opposite(X,Y). /* один мужик */

opposite(east,west).

opposite(west,east):-!. /* описание противоположных сторон */

23

unsafe( state(F,X,X,_) ):- opposite(F,X)

/* волк съедает козу */

unsafe( state(F,_,X,X) ):- opposite(F,X).

/* коза съедает капусту */

member(X,[X|_]).

member(X,[_|L]):-member(X,L) /* проверка состояний, которые уже были */

write_path( [H1,H2|T] ) :- !,

readchar(_), write_move(H1,H2), write_path([H2|T]). write_path( [ ] ).

write_move( state(X,W,G,C), state(Y,W,G,C) ) :-!, write(“ Мужик пересекает реку с”,X,” на “,Y),nl. write_move( state(X,X,G,C), state(Y,Y,G,C) ) :-!, write(“ Мужик везет волка с “,X,” берега на “,Y),nl. write_move( state(X,W,X,C), state(Y,W,Y,C) ) :-!, write(“ Мужик везет козу с”,X,” берега на “,Y),nl. write_move( state(X,W,G,X), state(Y,W,G,Y) ) :-!, write(“ Мужик везет капусту с “,X,” берега на “,Y),nl.

8. РЕШЕНИЕ ЛОГИЧЕСКИХ ЗАДАЧ

Способности к описанию логических задач являются наиболее сильной стороной ПРОЛОГа.

Многие логические задачи связаны с рассмотрением нескольких конечных множеств с одинаковым количеством элементов, между которыми устанавливается взаимно-однозначное соответствие. На языке Пролог эти множества можно описывать как базы данных, а зависимости между объектами устанавливать с помощью правил.

Рассмотрим простую логическую задачу. Пример:

«В велосипедных гонках три первых места заняли Алеша, Петя и Коля. Какое место занял каждый из них, если Петя занял не второе и не третье место, а Коля – не третье?»

Решение задачи заключается в установлении зависимости между спортсменами и местами, которую можно описать табл. 2 (прочерки указывают известную информацию):

24

 

 

 

Таблица 2

 

 

 

 

Имя

1-е место

2-е место

3-е место

 

 

 

 

Алеша

 

 

 

 

 

 

 

Петя

 

 

 

 

 

Коля

 

 

 

 

 

 

Очевидно, Петя может занимать только первое место, тогда Коля – только второе, а Алеше достается третье (табл. 3).

 

 

 

Таблица 3

 

 

 

 

Имя

1-e место

2-e место

3-e место

 

 

 

 

Алеша

+

 

 

 

 

Петя

+

 

 

 

 

Коля

+

 

 

 

 

При описании этой задачи на ПРОЛОГе получается следующая программа.

Программа 17

PREDICATES name(symbol) mesto(symbol) prizer(symbol,symbol)

solution(symbol,symbol,symbol,symbol,symbol,symbol) CLAUSES

name(alex). name(pier). name(nike). mesto(odin). mesto(dva). mesto(tri).

prizer(X,Y):-name(X),mesto(Y),X=pier,not(Y=dva),not(Y=tri); name(X),mesto(Y),X=nike,not(Y=tri); name(X),mesto(Y),not(X=pier),not(X=nike). solution(X1,Y1,X2,Y2,X3,Y3):-name(X1),name(X2),name(X3),

mesto(Y1),mesto(Y2),mesto(Y3),prizer(X1,Y1), prizer(X2,Y2), prizer(X3,Y3),Y1<>Y2,Y2<>Y3,Y1<>Y3, X1<>X2,X2<>X3,X1<>X3,!.

Конечно, в приведенном примере быстрее использовать таблицу для получения решения. Однако в более сложных случаях таблицы становятся многомерными. Рассмотрим еще один пример – логическую задачу (“Наука и жизнь” №3 , 1968):

25