/*демонстрация использования восходящей рекурсии */
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 (сумму вычислить и восходящей, и нисходящей рекурсией).