
- •Глава 1. Введение в пролог
- •1. Декларативные и процедурные языки программирования
- •2. Пролог и логика предикатов. Внешние цели
- •3. Управление программой. Подцели. Механизм сопоставления
- •4. Внутренние подпрограммы унификации
- •Глава 2. Внутренние цели. Механизм возврата
- •1. Структура пролог-программы
- •2. Использование внутренних целей
- •3. Встроенный предикат fail
- •4. Сокращенные варианты внутренних запросов
- •5. Использование в запросах анонимных переменных
- •6. Механизм возврата
- •Глава 3. Типы данных и арифметика Turbo Prolog
- •1. Стандартные типы данных
- •2. Структуры, простые и составные
- •3. Структурные диаграммы
- •4. Использование в запросах анонимных переменных
- •5. Использование альтернативных доменов
- •6. Арифметика в Turbo Prolog
- •Глава 4. Предикат отсечения (!). Программирование альтернатив. Правила повтора
- •1. Повторения и возвраты
- •2. Отсечение (!)
- •3. Программирование альтернатив
- •4. Правило повтора
- •Глава 5. Методы организации рекурсии
- •1. Простая рекурсия
- •2. Метод обобщенного правила рекурсии
- •3. Граничное условие рекурсии. Нисходящая и восходящая рекурсии
- •4. Программа о подсчете числа точек
- •Глава 6. Списки
- •1. Основные понятия
- •2. Списки и турбо-пролог
- •3. Атрибуты списка
- •4. Внутреннее представление списков
- •5. Применение списков в программе
- •6. Метод разделения списка на голову и хвост
- •7. Поиск элемента в списке
- •8. Присоединение списка
- •9. Добавление и удаление элемента
- •10. Подсписок
- •11. Перестановки списка
- •Глава 7. Сортировка списков
- •1. Разделение списка на два
- •2. Сортировка списков методом вставки
- •3. Быстрая сортировка
- •4. Быстрая сортировка_1
- •5. Компоновка данных в список
- •Глава 8. Программирование алгоритмов с возвратом. Представление графов в turbo prolog
- •1. Задача о весах
- •2. Представление графов в turbo prolog
- •3. Поиск пути на неориентированном графе
- •4. Поиск гамильтоновых циклов
- •5. Поиск пути минимальной стоимости
- •Глава 9. Динамическая база данных
- •1. Турбо-пролог и реляционные базы данных
- •2. Описание предикатов динамических бд
- •3. Встроенные предикаты asserta, assertz, retract, retractall, save, consult
- •4. Создание динамической базы данных
- •5. Обсуждение проекта базы данных
- •6. Создание базы данных
- •7. Написание программных модулей
- •Глава 10. Глобальные переменные в turbo prolog
- •1. Модификация базы данных
- •2. Накопление результатов с помощью вынуждаемого возврата
- •3. Подсчет членов парторганизации
- •4. Поиск пути минимальной стоимости от a до z
- •Библиографический список
- •Оглавление
3. Граничное условие рекурсии. Нисходящая и восходящая рекурсии
В самом общем виде рекурсия есть способ разбиения задачи на подзадачи, каждая из которых является уменьшенным вариантоми предыдущей. В итоге мы должны прийти к задаче, решаемой непосредственно.
Решить ее позволит утверждение, называемое ГРАНИЧНЫМ УСЛОВИЕМ.
В задаче о вычислении суммы таким условием является
sum_series2(1,1) :- !.
Для ответа на запрос sum_series2(4,X) последовательно вычислялись sum_series2(3,S1), sum_series2(2,S2), sum_series2(1,S3) (граничное условие).
Такая рекурсия называется НИСХОДЯЩЕЙ.
Поступим наоборот: начнем с граничного условия и будем строить решение, пока не получим исходную задачу.
Такая рекурсия называется ВОСХОДЯЩЕЙ.
В таком методе правило sum_series3 должно иметь два дополнительных параметра:
1) указание на размер решенной к данному моменту задачи (число уже просуммированных слагаемых);
2) запись промежуточного решения (уже подсчитанной частичной суммы).
Запрос
sum_series3(1,1,7,X)
включает старое граничное условие, как уже решенную к настоящему моменту задачу.
Новое граничное условие выглядит так:
sum_series3(N,X,N,X):-!.
Правило 3 рекурсии:
/* M-текущее слагаемое, S-частичная сумма, N-последнее слагаемое, X-окончательная сумма */
sum_series3(M,S,N,X):-
M1=M+1,
S1=S+M1,
sum_series3(M1,S1,N,X).
Упражнение 5.2.
Вычислить и напечатать факториал числа 5 с помощью восходящей и нисходящей рекурсии.
4. Программа о подсчете числа точек
/* Программа 5.2 «Подсчет точек». Назначение: */
/*демонстрация использования восходящей рекурсии */
constants
r=2
domains
i=integer
r=real
predicates
show_point
culc_point(i,i,i,i,i,i)
pos_point(i,i,i,r,r,i,i,i)
out_sqr(r,r)
in_circ(r,r)
goal
show_point.
clauses
show_point:-
clearwindow,
% запрос с обнуленными счетчиками точек
culc_point(0,0,0,Sum1,Sum2,Sum3),
write("вне квадрата ",Sum1,
"внутри круга ",Sum2,
"в квадрате вне круга ",Sum3).
% рекурсивное правило
culc_point(C1,C2,C3,Sum1,Sum2,Sum3):-
write(" X? "),readreal(X),
write(" Y? "),readreal(Y),
pos_point(C1,C2,C3,X,Y,S1,S2,S3),!,nl,
% вызов с новыми значениями счетчиков
culc_point(S1,S2,S3,Sum1,Sum2,Sum3).
% выход из рекурсии с накопленными счетчиками
culc_point(C1,C2,C3,C1,C2,C3).
% окончание запросов и отказ процедуры
% pos_point
pos_point(_,_,_,0,0,_,_,_):-!,fail.
% увеличение первого счетчика
pos_point(C1,C2,C3,X,Y,S1,C2,C3):-
S1=C1+1,
out_sqr(X,Y),!,
write(" вне квадрата").
% увеличение второго счетчика
pos_point(C1,C2,C3,X,Y,C1,S2,C3):-
S2=C2+1,
in_circ(X,Y),!,
write("внутри круга").
% увеличение третьего счетчика
pos_point(C1,C2,C3,_,_,C1,C2,S3):-
S3=C3+1,
write("вне круга и внутри квадрата").
% условие для точки вне квадрата
out_sqr(X,Y):-
abs(X)>r;
abs(Y)>r.
% условие для точки внутри круга
in_circ(X,Y):-
X*X+Y*Y<r*r.
/* Конец программы */
Программа 5.2 содержит восходящую рекурсивную процедуру culc_point, благодаря которой происходит подсчет точек.
Первый вызов ее из цели верхнего уровня —
culc_point(0,0,0,Sum1,Sum2,Sum3), где первые три аргумента — текущие значения счетчиков, оставшиеся — конечные значения (сейчас они не имеют никакого значения и являются свободными переменными).
Эта цель сопоставляется с рекурсивным правилом
culc_point(C1,C2,C3,Sum1,Sum2,Sum3), которое
1) запрашивает точку;
2) вызывает pos_point(C1,C2,C3,X,Y,S1,S2,S3), возвращающую новые значения счетчиков S1, S2, S3;
3) вызывает само себя с новыми текущими значениями счетчиков.
На протяжении всех этих вызовов последние три аргумента Sum1, Sum2, Sum3 остаются свободными переменными. Так продолжается до тех пор, пока не вводится точка (0,0).
Правило pos_point(_,_,_,0,0,_,_,_) дает отказ без возможности перехода на другое правило pos_point (комбинация !,fail), и рекурсивное правило culc_point дает отказ. Затем происходит переход на граничное условие culc_point(C1,C2,C3,C1,C2,C3).
Аргументы, предназначенные для конечных значений счетчиков, наконец, перестают быть свободными, — в них копируются текущие значения. После этого цель culc_point(0,0,0,Sum1,Sum2,Sum3) успешно согласуется, происходит печать ответов и выход из программы.
Упражнение 5.3.
Напечатать
сумму ряда
,
вычисленную с заданной точностью eps при
фиксированном значении x (сумму вычислить
и восходящей, и нисходящей рекурсией).