Navision и рекурсия
Статья — вольный перевод статьи Алена Крикилайона http://mibuso.com/howtoinfo.asp?FileID=11
Что такое рекурсия
Рекурсия — это функция, которая вызывает самое себя. Это может происходить явно (функция XYZ содержит в своем теле вызов XYZ), либо неявно (в функции XYZ есть вызов функции ABC, в которой есть вызов функции KLM, в которой… и прочая, и прочая, и, наконец, в которой есть вызов функции XYZ).
Шаблон функции, использующей рекурсию
Function RecursiveFunction(Parameters): Optional RETURN-VALUE
BEGIN
IF {End-Condition} THEN
EXIT(Some Return-Value);RecursiveFunction(Parameters); // Возможны несколько вызовов
Тело функции, изменения в переменных
RecursiveFunction(Parameters); // Снова вызов рекурсии, также возможно несколько раз
END;Некоторые замечания по поводу рекурсии
Самая важная в рекурсии вещь — знать, когда надо ее (рекурсию) остановить.
Вторая важная вещь — переменные, которые вы используете в рекурсии, должны быть объявлены локально (в пределах функции). Исключения возможны, но их необходимо делать осознанно.
Рекурсия работает медленнее чем т.н. программирование итераций, за счет того, что при каждом вызове рекурсивной функции в стек сначала помещается, а затем извлекается большой объем информации — локальные переменные, информация по самой функции. Тем не менее, при разработке приложений для БД, на это можно практически не обращать внимания, поскольку падение производительности при рекурсии исчисляется микросекундами, а доступ в базе измеряется миллисекундами.
У всякой рекурсии есть предел по количеству вложенных вызовов. Это связано с ограничением по размеру стека. При нехватке стека вы получите ошибку.
Классические примеры рекурсии
Первый пример — функция суммы SUM(N) = 1 + 2 + … + N
Function Sum(Iint : INTEGER): INTEGER
BEGIN
IF Iint = 0 THEN
EXIT(0);
EXIT(Iint + Sum(Iint — 1));
END
Эта функции имеет Iint уровней вложенности, так что существует возможность того, что вам не хватит размеров стека.
Следущая реализация позволяет избежать этой проблемы (хотя и не полностью). Посколько уровней вложенности в ней сего LOG2(N) — логарифм N по основанию 2. Попробуйте сами сделать вызов Sum(50000) в обоих случаях и посмотрите на результат (в первом случае — Stack Overfow, во втором — результат).
Function Sum(Iint : INTEGER) : INTEGER
BEGIN
EXIT(Sum2(0,Iint));
END
Function Sum2(IintFrom : INTEGER;IintTo : INTEGER) : INTEGER
Local variable : Lint: INTEGER // this must be a local variable!
BEGIN
IF IintFrom = IintTo THEN
EXIT(IintFrom);
Lint := (IintTo + IintFrom) DIV 2;
EXIT(sum2(IintFrom,Lint) + sum2(Lint + 1,IintTo));
END;
Приложения
В прилагаемом fob-файле 2 отчета:
Report 50000 — показывает все комплекты с комплектующими товарами, и для каждого ребенка — всех его детей, и т.д.
Report 50001 — представьте, что вам необходимо узнать, из скольких компонентов (и в каком количестве) состоит комплект. Этот отчет проходит по всему содержимому комплекта и выводит полный список компонент одним списком.
![](http://1.gravatar.com/avatar/7e296bc11c5b3783f842bdd31c05f031?s=55&d=http%3A%2F%2Fnaviart.ru%2Fwp-content%2Fthemes%2Farticle-directory%2Fi%2Fanonymous.png&r=g)
Автор: Андрей Стрельников
В области Navision - с 2003 года. Профессиональные интересы: NAV, MS SQL, .NET, BPMN, IT-менеджмент. Предметная область: логистика, финансы, склады, 3PL.
Количество статей, опубликованных автором: 86.