Опубликован: 12.02.2014 | Доступ: свободный | Студентов: 818 / 236 | Длительность: 11:22:00
Специальности: Программист
Лекция 5:

Рекурсия

< Лекция 4 || Лекция 5: 1234 || Лекция 6 >
Аннотация: Рекурсивное программирование является в логических языках основным видом программирования. Эффективность рекурсивных программ повышается с помощью хвостовой рекурсии. Рассматриваются виды рекурсии и рекурсивные алгоритмы. Кроме этого, вводятся понятие функции и понятие предикатного домена в языке Visual Prolog.

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

В настоящей главе рассматриваются виды рекурсии и рекурсивные алгоритмы. Кроме этого, вводятся понятие функции и понятие предикатного домена в языке Visual Prolog.

5.1. Рекурсивное определение отношений

Определение рекурсивного предиката состоит в указании базиса рекурсии и шага рекурсии, так что в нем участвуют как рекурсивные правила, в которых предикат описывается через самого себя, так и правила, не являющиеся рекурсивными.

Основным недостатком рекурсивного программирования является большой расход памяти. Для каждого вызова рекурсивного предиката запоминается его состояние, чтобы можно было вернуться к нему впоследствии.

Рассмотрим определение факториала целого неотрицательного числа:

n! = 1 \cdot 2 \cdot  ... \cdot (n – 1) \cdot n.

Очевидно, что n! = n \cdot (n – 1)!. Соответственно, определим рекурсивно предикат fact/2 следующим образом:

class predicates
    fact: (positive, unsigned64 [out]).
clauses
    fact(0, 1):- !.            % 1 правило
    fact(N, F):- fact(N - 1, X), F = N * X.    % 2 правило

Проследим ход поиска решений для цели

fact(3, R).

Данная цель не унифицируется с заголовком первого правила, но унифицируется с заголовком второго правила, которое имеет вид (напомним, что переменные в правилах автоматически переименовываются):

fact(N1, F1):- fact(N1 - 1, X1), F1 = N1 * X1.
Имеем: N1 = 3, F1 = R. Новая цель имеет вид:
fact(2, X1), R = 3 * X1.

Сначала вызывается подцель

fact(2, X1).

Она также не унифицируется с заголовком первого правила, но унифицируется с заголовком второго:

fact(N2, F2):- fact(N2 - 1, X2), F2 = N2 * X2.

При этом N2 = 2, F2 = X1. Следующая цель имеет вид:

fact(1, X2), X1 = 2 * X2, R = 3 * X1.

Вызывается подцель

fact(1, X2).

Эта подцель также унифицируется с заголовком только второго правила:

fact(N3, F3):- fact(N3 - 1, X3), F3 = N3 * X3.

При этом N3 = 1, F3 = X2. Следующая цель выглядит так:

fact(0, X3), X2 = 1 * X3, X1 = 2 * X2, R = 3 * X1.

Вызывается первая подцель

fact(0, X3).

Она унифицируется с заголовком правила

fact(0, 1):- !.

При этом X3 = 1. В теле этого правила стоит отсечение, поэтому других решений быть не может. Полученное значение передается в оставшуюся цель

X2 = 1 * X3, X1 = 2 * X2, R = 3 * X1.

Из первой подцели находится значение X2 = 1. Оно передается в цель

X1 = 2 * X2, R = 3 * X1.

Из первой подцели следует, что X1 = 2. Это значение передается в цель

R = 3 * X1.

Таким образом, получено решение

R = 6.

Данная рекурсия является нисходящей. Нисходящая рекурсия последовательно разбивает задачу на все более простые, пока не доходит до граничной ситуации, в которой уже не требуется продолжения рекурсии.

В целях повышения эффективности вычислений перейдем к хвостовой рекурсии. Рекурсия — хвостовая, если вызов предиката самого себя идет последним в правиле, при этом до него нет недетерминированных вызовов. Хвостовая рекурсия соответствует итерации в процедурных языках программирования.

< Лекция 4 || Лекция 5: 1234 || Лекция 6 >
Жаныл Айкын
Жаныл Айкын
Rustam Inatov
Rustam Inatov

Доброго времени суток, подскажите пожалуйста, visual prolog examples, pie, vip7.5 - это все, где я могу скачать? (в смысле) может быть на сайте есть какой-то архив? Увы я не нашел его.

Подскажите, пожалуйста.

С уважением, Рустам.