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 — представьте, что вам необходимо узнать, из скольких компонентов (и в каком количестве) состоит комплект. Этот отчет проходит по всему содержимому комплекта и выводит полный список компонент одним списком.

Автор:

В области Navision - с 2003 года. Профессиональные интересы: NAV, MS SQL, .NET, BPMN, IT-менеджмент. Предметная область: логистика, финансы, склады, 3PL.

Количество статей, опубликованных автором: 86.

Добавить комментарий