Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Логическое программирование_УП

.pdf
Скачиваний:
90
Добавлен:
11.05.2015
Размер:
943.35 Кб
Скачать

141

inc,

N1 is N-1, ackerman(M,N1,Val1), M1 is M-1, ackerman(M1,Val1,Val).

inc:-

do(X),

X1 is X+1, retract(do(_)), assert(do(X1)).

do(0).

?- ackerman(3,2,X),do(Y). X = 29

Y = 541 Yes

В данном случае предикат ackerman вызвал себя рекурсивно 541 раз. Теперь приведем вариант с запоминающей функцией.

:- dynamic do/1,ackerman/3.

ackerman(0,N,N1):- inc,

N1 is N+1.

ackerman(M,0,Val):- M>0, inc,

M1 is M-1, lemma(ackerman(M1,1,Val)).

ackerman(M,N,Val):- M>0,N>0, inc,

N1 is N-1, lemma(ackerman(M,N1,Val1)), M1 is M-1, lemma(ackerman(M1,Val1,Val)).

142

lemma(P):-

P, asserta((P:-!)).

do(0).

inc:-

do(X),

X1 is X+1, retract(do(_)), assert(do(X1)).

?- ackerman(3,2,X),do(Y). X = 29

Y = 73 Yes

Теперь предикат ackerman вызывает себя только 73 раза. Приведем замечание из [2, стр. 164]. Приведенные примеры

показывали некоторые, безусловно удобные способы применения предикатов assert и retract. Но при использовании этих предикатов необходимо соблюдать особую осторожность. Излишнее и непродуманное применение этих средств нельзя рекомендовать в качестве хорошего стиля программирования. Использование операций подтверждения и извлечения фактов и правил по сути приводит к модификации программы. Поэтому отношения, которые в какой-то момент были действительными, в другое время могут оказаться недействительными. В разное время на одни и те же вопросы система будет давать разные ответы. Поэтому применение значительного количества операций подтверждения и извлечения может затемнить смысл программы. В конечном итоге может оказаться, что поведение программы трудно понять, нелегко объяснить, и поэтому ей нельзя доверять.

143

ЛИТЕРАТУРА

1. Robinson J.A. A machine-oriented logic based on resolution principle. Journal of the ACM, 12: 23–41, 1965.

2.Братко И. Алгоритмы искусственного интеллекта на языке PROLOG: Пер. с англ. — 3-е изд. — М.: Издательский дом

«Вильямс», 2004. — 640 с.

3.В.А. Антимиров, А.А. Воронков, А.И. Дегтярёв, М.В. Захарьящев, В.С. Проценко. Математическая логика в программировании. Обзор // Математическая логика в программировании:

Сб. статей 1980–1988 гг.: Пер. с англ. — М.: Мир, 1991. — 408 с.

4.Грэй П. Логика, алгебра и базы данных: Пер. с англ. — М.: Машиностроение, 1989. — 359 с.

5.Дейкстра Э. Заметки по структурному программированию // У. Дал, Э. Дейкстра, К. Хоор. Структурное программирование. —

М.: Мир, 1975. — С. 7–97.

6.Малпас Дж. Реляционный язык Пролог и его применение. —

М.: Наука, 1990. — 464 с.

7.Одинцов И.О. Профессиональное программирование. Системный подход. — СПб.: БХВ-Петербург, 2002. — 512 с.

8.Стерлинг Л., Шапиро Э. Искусство программирования на языке Пролог. — М.: Мир, 1990. — 235 с.

9.Язык Пролог в пятом поколении ЭВМ: Сб. статей, 1983– 1986 гг. / Сост. Н.И. Ильинский. — М.: Мир, 1988.

144

ПРИЛОЖЕНИЕ

Помощь в SWI-Prolog’е

После инсталляции интерпретатора SWI-Prolog есть возможность обратиться к помощи через ярлык «manual.html». Кроме того, документация для пользователя находится в файле manual.pdf (читается с помощью программы Adobe Acrobat).

Кроме того, SWI-Prolog имеет помощь online. Вызов «?- help(<имя предиката>).» выдает на экран информацию об этом предикате. Вызов «?- help.» выдает информацию о том, как пользоваться этой помощью.

Трассировка выполнения программы

Предикат trace позволяет пользователю отслеживать состояние интерпретатора Пролога.

trace/0

Стартует трассировщик. В процессе мониторинга в выходной файл выводятся все целевые утверждения, обрабатываемые интерпретатором языка. Зачастую этой информации для пользователя слишком много.

trace(+Pred)

Эквивалентно вызову trace(+Pred, +all).

trace(+Pred, + Ports)

Устанавливаются точки трассировки на всех предикатах, удовлетворяющих спецификации Pred. Ports есть список портов

(call, redo, exit, fail). Атом all ссылается на все пор-

ты. Если перед именем порта стоит символ «–», то данный порт не трассируется. Знак «+» говорит о том, что установлена трассировка данного порта.

При трассировке предиката получаем следующую информа-

цию:

1)уровень глубины рекурсивных вызовов;

2)когда предпринимается первая попытка обработки целевого утверждения (порт call);

3)когда цель успешно достигнута (порт exit);

4)возможность других соответствий целевому утверждению (порт redo);

145

5) невозможность достижения цели, поскольку все попытки завершились неудачно (порт fail).

Примеры:

?- trace(hello). % трассировка всех портов предиката hello с любой арностью ?- trace(foo/2, +fail). % трассировка неудач при вызове foo/2

?- trace(bar/1, -all). % прекращение трассировки bar/1.

Проведем трассировку для программы:

родитель( пэм, боб). родитель( том, боб). родитель( том, лиз). родитель( боб, энн). родитель( боб, пэт). родитель( пэт, джим).

предок(X,Y):-

родитель(X,Y).

предок(X,Y):-

родитель(X,Z), предок(Z,Y).

?- trace(родитель).

%

родитель/2: [call, redo, exit, fail]

Yes

 

 

[debug]

?- trace(предок).

%

предок/2: [call, redo, exit, fail]

Yes

 

 

[debug]

?- предок(том,пэт).

T Call:

(6)

предок(том, пэт)

T Call:

(7)

родитель(том, пэт)

T Fail:

(7)

родитель(том, пэт)

T Redo:

(6)

предок(том, пэт)

T Call:

(7)

родитель(том, _G414)

T Exit:

(7)

родитель(том, боб)

T Call:

(7)

предок(боб, пэт)

T Call:

(8)

родитель(боб, пэт)

T Exit:

(8)

родитель(боб, пэт)

T Exit:

(7)

предок(боб, пэт)

T Exit:

(6)

предок(том, пэт)

Yes