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

Рекурсия

< Лекция 4 || Лекция 5: 1234 || Лекция 6 >

Рассмотрим другое определение факториала. В нем используются счетчик C и накопитель для хранения произведения первых C натуральных чисел:

class predicates
    fact: (positive, unsigned64 [out]).
    fact1: (positive, positive, unsigned64, unsigned64 [out]).
clauses
    fact(N, F):- fact1(N, 0, 1, F).

    fact1(N, N, F, F):- !.
    fact1(N, C, X, F):- fact1(N, C + 1, (C + 1) * X, F).

Снова проследим вычисления для цели fact(3, R). Эта цель унифицируется с заголовком правила:

fact(N1, F1):- fact1(N1, 0, 1, F1).

При этом N1 = 3, F1 = R. Далее вызывается цель

fact1(3, 0, 1, R).

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

fact1(N2, C2, X2, F2):- fact1(N2, C2 + 1, (C2 + 1) * X2, F2).

При этом N2 = 3, C2 = 0, X2 = 1, F2 = R. Теперь вызывается цель

fact1(3, 1, 1, R).

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

fact1(N3, C3, X3, F3):- fact1(N3, C3 + 1, (C3 + 1) * X3, F3).

При этом N3 = 3, C3 = 1, X3 = 1, F3 = R. Вызывается цель:

fact1(3, 2, 2, R).

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

fact1(N4, C4, X4, F4):- fact1(N4, C4 + 1, (C4 + 1) * X4, F4).

Теперь N4 = 3, C4 = 2, X4 = 2, F4 = R. Новая цель имеет вид:

fact1(3, 3, 6, R).

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

fact1(N5, N5, F5, F5):- !.

При этом N5 = 3, F5 = 6, R = 6. Отсечение предотвращает поиск других решений. Итак, имеем: R = 6.

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

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

Рассмотрим недетерминированный рекурсивный предикат. В следующей программе рекурсивно определяется отношение "предок" как транзитивное замыкание отношения "родитель" (рис. 5.1).

 Отношение "предок"

Рис. 5.1. Отношение "предок"
class facts - relatives
    parent: (string Родитель, string Ребенок).
clauses
    parent("Иван", "Мария").
    parent("Анна", "Мария").
    parent("Мария", "Павел").
    parent("Мария", "Петр").
    parent("Петр", "Степан").

class predicates
    ancestor: (string Предок, string Потомок) nondeterm (o,o) (i,o).
clauses
    ancestor(X, Y):-
        parent(X, Y).
    ancestor(X, Y):-
        parent(X, Z),
        ancestor(Z, Y).

    run():-
        ancestor(X, Y),
            write(X, " - ", Y), nl,
        fail;
        _ = readLine().
Пример 5.1. "Предок"

Упражнение 1.

  1. Постройте дерево поиска для цели

    ancestor("Мария", D).
    
  2. Определите отношение "потомок" как транзитивное замыкание отношения "родитель".
< Лекция 4 || Лекция 5: 1234 || Лекция 6 >
Жаныл Айкын
Жаныл Айкын
Rustam Inatov
Rustam Inatov

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

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

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