На этом шаге мы рассмотрим примеры использования рекурсии по аргументам.
Будем говорить, что рекурсия простая, если вызов функции встречается в некоторой ветви программы лишь один раз. Простой рекурсии в императивном программировании соответствует обыкновенный цикл.
Если в качестве результата функция возвращает значение другой функции, и рекурсивный вызов участвует в вычислении аргументов этой функции, то будем говорить о присутствии в функции рекурсии по аргументам.
(DEFUN FACT (LAMBDA (X)
(COND ( (ZEROP X) 1 )
( T (* X (FACT (- X 1))) )
)
))
(DEFUN COPY (LAMBDA (LST)
(COND ( (NULL LST) NIL )
( T (CONS (CAR LST) (COPY (CDR LST))))
)
))
Построенная функция COPY является рекурсивной по аргументу, т.к. рекурсивный вызов является аргументом функции CONS. Функция COND в теле функции содержит две ветви: ветвь с условием окончания и ветвь с рекурсией, с помощью которой функция проходит список, копируя и укорачивая в процессе этого список по направлению CDR или, как говорят, в ширину.
Копирование списков представляет собой одно из основных действий над списками, и поэтому соответствующая функция входит в число встроенных функций практически во всех LISP-системах.
(DEFUN DROPLAST (LAMBDA (LST)
(REVERSE (CDR (REVERSE LST)))
))
(DEFUN REMOVEF (LAMBDA (X LST)
(COND ( (NULL LST) NIL )
( (EQ X (CAR LST)) (CDR LST) )
( T (CONS (CAR LST) (REMOVEF X (CDR LST))) )
)
))
Тестовый пример:
$ (REMOVEF (A B) (A B (A B) C (A B)))
(A B C (A B))
(DEFUN EVERYSECOND (LAMBDA (L)
(COND ( (NULL L) NIL )
( (NULL (CDR L)) L )
( T (CONS (CAR L) (EVERYSECOND (CDDR L))) )
)
))
(DEFUN MAXIM (LAMBDA (LST)
(COND ( (NULL LST) NIL )
( (EQ (LENGTH LST) 1) (CAR LST) )
( T (MAX2 (CAR LST) (MAXIM (CDR LST))) )
)
))
; ---------------------
(DEFUN MAX2 (LAMBDA (X Y)
(( (> X Y) X )
Y )
))
Какие исправления необходимо проделать в программе, чтобы получить наименьший элемент одноуровневого списка?
(DEFUN CHEREDUJ (LAMBDA (X Y)
(COND ( (NULL X) Y )
( T (CONS (CAR X) (CHEREDUJ Y (CDR X))) )
)))
(DEFUN NINSERT (LAMBDA (X LST)
(COND ( (NULL LST) 0)
( (EQ X (CAR LST))
(+ 1 (NINSERT X (CDR LST)) ) )
( T (NINSERT X (CDR LST)) )
)))
(DEFUN SUMMA (LAMBDA (LST)
(COND ( (NULL LST) 0)
( T (+ (CAR LST) (SUMMA (CDR LST))) )
)
))
(DEFUN LENGTH_1 (LAMBDA (LST)
(COND ( (NULL LST) 0 )
( T (+ 1 (LENGTH_1 (CDR LST))) )
)
))
Отметим, что если применять эту функцию к списку списков, то элементы NIL, которые заключают каждый список, будут также учитываться!
(DEFUN INSERT (LAMBDA (X N LST)
(COND ( (NULL LST) (CONS X LST) )
( (EQ N 1) (CONS X LST) )
( T (CONS (CAR (LST))
(INSERT X (DIFFERENCE N 1)
(CDR LST)))
)
)
))
(DEFUN DOUBLE (LAMBDA (L)
(COND ( (NULL L) NIL )
( (NULL (CDR L)) NIL )
( T (CONS (LIST (CAR L) (CADR L))
(DOUBLE (CDDR L))) )
)
))
(DEFUN SASHA (LAMBDA (X Y)
(COND ( (NULL X) )
( T (LIST (CAR X) (CAR Y)
(SASHA (CDR X) (CDR Y)))
)
)
))
(DEFUN UNIT (LAMBDA (X Y)
(COND ( (NULL X) NIL)
( (EQ (LENGTH X) 1)
(LIST (CAR X) (CAR Y)) )
( T (LIST (LIST (CAR X) (CAR Y))
(UNIT (CDR X) (CDR Y))) )
)
))
(DEFUN COLLECT (LAMBDA (LST)
(COND ( (NULL LST) NIL )
( T (CONS (CAR LST)
(COLLECT (COND ( (MEMBER (CAR LST)
(CDR LST))
(CONS (CAR LST)
(REMOVEF
(CAR LST)
(CDR LST))))
( T (CDR LST))))) )
)
))
; --------------------------
(DEFUN REMOVEF (LAMBDA (X LST)
(COND ( (NULL LST) NIL )
( (EQ X (CAR LST)) (CDR LST) )
( T (CONS (CAR LST) (REMOVEF X (CDR LST))) )
)
))
(DEFUN COUNT (LAMBDA (LST) ; Подсчет количества положительных, отрицательных и ; нулевых элементов числового списка LST (LIST (SUMMA LST PLUSP) (SUMMA LST ZEROP) (SUMMA LST MINUSP)) )) ; --------------------------- % (DEFUN SUMMA (LAMBDA (LST FUNC) ; Подсчет количества элементов числового списка, ; для которых предикат FUNC истинен (COND ( (NULL LST) 0 ) ( (FUNC (CAR LST)) (+ 1 (SUMMA (CDR LST))) ) ( T (SUMMA (CDR LST)) ) ) ))
(DEFUN FIRST (LAMBDA (LST)
(COND ( (NULL LST) NIL)
( (ODDP (CAR LST))
(CONS (* (CAR LST) (CAR LST))
(CDR LST)) )
( T (CONS (CAR LST) (FIRST (CDR LST))) )
)
))
(DEFUN ALL (LAMBDA (LST)
(COND ( (NULL LST) NIL)
( (ODDP (CAR LST))
(CONS (* (CAR LST) (CAR LST))
(ALL (CDR LST))) )
( T (CONS (CAR LST) (ALL (CDR LST))) )
)
))
(DEFUN ROM (LAMBDA (N)
(COND ( (NOT (< N 1000))
(CONS M (ROM (- N 1000))) )
( (NOT (< N 500))
(CONS D (ROM (- N 500))) )
( (NOT (< N 100))
(CONS C (ROM (- N 100))) )
( (NOT (< N 50))
(CONS L (ROM (- N 50))) )
( (NOT (< N 10))
(CONS X (ROM (- N 10))) )
( (NOT (< N 5))
(CONS V (ROM (- N 5))) )
( (NOT (< N 1))
(CONS I (ROM (- N 1))) )
)
))
(DEFUN GORNER (LAMBDA (COEF N X)
(COND ( (EQ N 0) (NTH 1 COEF) )
( T (+ (NTH 1 COEF)
(* X (GORNER (CDR COEF)
(- N 1)
X)
)
)
)
)
))
; ----------------------
(DEFUN NTH (LAMBDA (N LST)
; Функция возвращает N-й элемент списка LST
(COND ( (EQ N 1) (CAR LST) )
( T (NTH (- N 1) (CDR LST) ) )
)
))
На следующем шаге мы рассмотрим рекурсию по значению.