Если вам нужно рекурсивно работать со списком, вам следует подумать о двух вещах: случай завершения, например, что происходит, когда список пуст, и рекурсивный случай, например, что происходит, когда список имеет по крайней мере один элемент.
В вашем случае, когда список пуст, ни один номер не должен быть в квадрате, поэтому верните пустой список. В противном случае вы должны построить (т.е. cons
) новый список, первый элемент которого является квадратом первого элемента списка (т.е. (car x)
), а остальная часть списка получается путем возведения в квадрат остальной части списка ( т.е. (cdr x)
).
Вот возможное решение вашей проблемы:
CL-USER> (defun square-list (x)
(if (null x)
nil
(cons (* (car x) (car x)) (square-list (cdr x)))))
SQUARE-LIST
CL-USER> (square-list '(1 2 3 4 5))
(1 4 9 16 25)
Кстати, вы можете взять только списки car
и cdr
, не из атомов (это приведет к ошибке времени выполнения).
CL-USER> (car (list 1 2 3 4 5))
1
CL-USER> (cdr (list 1 2 3 4 5))
(2 3 4 5)
CL-USER> (car 1)
The value 1 is not of the expected type LIST.
[Condition of type TYPE-ERROR]
Если вместо этого вам нужно поместить все элементы дерева (т.е. список, содержащий произвольно вложенный подсписок), то вам нужно чтобы изменить функцию для управления тремя разными случаями, а не двумя:
- , если список пуст, возвращает пустой список,
- , если первый элемент списка сам по себе является список, затем примените к нему рекурсивно
square-list
и «против» результата, полученного с применением square-list
к остальной части списка, - в противном случае, верните новый список, возведя в квадрат первый элемент списка (который теперь мы знаем, что это, безусловно, атом) и «с onsing »результат с результатом возведения в квадрат остальной части списка.
Например:
CL-USER> (defun square-list (x)
(cond ((null x) nil)
((listp (car x)) (cons (square-list (car x))
(square-list (cdr x))))
(t (cons (* (car x) (car x)) (square-list (cdr x))))))
SQUARE-LIST
CL-USER> (square-list '(1 ((2 3) (4))))
(1 ((4 9) (16)))
В качестве последних замечаний, обратите внимание, что вышеуказанная функция не является хвостовой рекурсивной. Самый простой способ сделать хвостовую рекурсию первым - использовать классическую стратегию «накопителя».
CL-USER> (defun square-list (x &optional accumulator)
(if (null x)
(reverse accumulator)
(square-list (cdr x) (cons (* (car x) (car x)) accumulator))))
SQUARE-LIST
CL-USER> (square-list '(1 2 3 4 5))
(1 4 9 16 25)