Пятница, 22.11.2024, 14:25
Приветствую Вас Гость | RSS | PDA

Всё для студента информата

Полезная информация

Материалы для студента

Всё для студента IT » Материалы для студента » Функциональное программирование

Рекурсия более высокого порядка

Выразительные возможности рекурсии уже видны из приведенных выше содержательных и занимающих мало места определений. Определения функций В-ОДИН-УРОВЕНЬ и ОБРАЩЕНИЕ в итератив­ном варианте не поместились бы на одни лист бумаги (попробуйте!). С помощью рекурсии легко работать с динамическими, заранее не определен­ными целиком, но достаточно регулярными  структурами, такими как списки произвольной длины и глубины вложения.

Используя все более мощные виды рекурсии, можно записывать относительно лаконичными средст­вами и более сложные вычисления. Одновременно с этим, поскольку определения довольно абстрактны, растет сложность программирования и понимания программы.
Рассмотрим теперь программирование вложенных циклов в такой форме, при которой в определении функции рекурсивный вызов является аргументом вызова этой же самой функции. В такой рекурсии можно выделить различные порядки (order) в соответс­твии с тем, на каком уровне рекурсии находится вызов. Такую форму рекурсии будем называть рекурсией более высокого порядка. Функции, которые мы до сих пор определяли, были функциями с рекурсией нулевого порядка.

В качестве классического примера рекурсии более высокого порядка часто приводится известная из теории рекурсивных функций, функция Аккермана, пользующаяся славой "плохой" функции:

_(defun AKKEPMAH (m n)
(cond ((= m 0) (+ n 1))
((= n 0) (AKKEPMAH (- m 1) 1))
(t (AKKEPMAH (- m 1)
(AKKEPMAH m (- n 1))))))
AKKEPMAH
(аккерман 2 2)
7
(аккерман 3 2)
27

Функция Аккермана является функцией с рекурсией первого порядка. Ее вычисление довольно сложно, и время вычисления растет лавинообразно уже при малых значениях аргумента.

В качестве другого примера функции с рекурсией первого порядка приведем функцию В-ОДИН-УРО ВЕНЬ, располагающую элементы списка на одном уровне, которую мы ранее определили, используя параллельную рекурсию:

_(defun в-один-уровень (1)
(уровень 1 nil))
В-ОДИН-УРОВЕНЬ
_(defun ВЫРОВНЯТЬ (l результат)
(cond ((null l) результат)
((atom l) (cons l результат))
(t (ВЫРОВНЯТЬ (cdr l) результат)))))

В этом определении работа функции непосредственно сведена к базовым функциям и рекурсии первого порядка, где аргументом рекурсивного вызова является один рекурсивный вызов. В более раннем определении дополнительно к базовым функциям и рекурсии нулевого порядка мы использовали функцию APPEND. Применяя рекурсию более высокого порядка вычисле­ния можно представить более абстрактно и с помощью более короткого определения, однако представить себе работу такой функции довольно сложно.

Функция ВЫРОВНЯТЬ работает следующим обра­зом. Результат строится в списке РЕЗУЛЬТАТ. Если L - атом, то его можно непосредственно добавить в начало списка РЕЗУЛЬТАТ. Если L - список и его первый элемент является атомом, то все сводится к предыдущему состоянию на следующем уровне рекурсии, но в такой ситуации, когда список РЕЗУЛЬТА! содержит уже вытянутый в один уровень оставшийся хвост.
В том случае, когда и голова списка L является списком, то его сначала приводят к одному уровню. Это делается с помощью рекурсивных вызов, погру­жающихся з головную ветвь до тех пор, пока там не встретится атом, который можно добавить в начале вытянутой к этому моменту в один уровень структуры. Встречающиеся таким образом атомы добавляются по одному к вытянутому хвосту. На каждом уровне при исчерпании списка на предыдущий уровень выдается набранный к данному моменту РЕЗУЛЬТАТ.

Следующее определение функции REVERSE, ис­пользующей лишь базовые функции и рекурсию, является примером еще более глубокого уровня рекурсии:

_(defun REV (1)
(cond
((null l) 1)
((null (cdr l)) 1)
(t (cons
(car (REV (cdr l)))
(REV (cons (car l)
(REV (cdr (REV (cdr l) ))))))

В определении использована рекурсия второго порядка. Вычисления, представ­ленные этим определением, понять труд­нее, чем прежние. Сложная рекурсия усложняет и вычисления. В этом случае невозможно вновь воспользоваться полученными ранее результатами, поэтому одни и те же результаты приходится вычислять снова и снова. Обращение списка из пяти элементов функцией REV требует 149 вызовов. Десятиэлементный список требует уже 74 409 вызовов и заметное время для вычисления! Как прави­ло, многократных вычислений можно избежать, разбив определение на несколько частей и используя подходящие параметры для сохранения и передачи промежу­точных результатов.
Обычно в практическом программировании формы рекурсии более высокого порядка не используются, но у них по крайней мере есть свое теоретическое и методологическое значение.

Похожие статьи:

Не нашли то, что Вам нужно?.. Найдите ответ на форуме!
Категория: Функциональное программирование | Добавил: admin (04.11.2010)
Просмотров: 1785 | Теги: лекция, статья
Сообщество
Помощь
Форма входа
Поиск

Студенческий помощник по информатике © 2024
При цитировании материалов данного сайта, обязательна ссылка на источник: ITstudents.ru



>