У вас есть только незначительные ошибки. Сначала нам нужно избавиться от output
и (output)
;они не имеют никакого отношения к коду. Кажется, вы работали с переменной с именем output
, а затем переименовали ее в out
, не исправляя весь код. Более того, (output)
- это вызов функции;он ожидает, что существует функция с именем output
.
Во-вторых, результат append
должен быть каким-то образом зафиксирован;в progn
вы просто отбрасываете это. Вот рабочая версия:
(defun foo (in i out)
(if (>= i 0)
(foo in (1- i) (cons (intern (string (elt in i))) out))
out))
Обратите внимание, что вместо вашего (append (list X) Y)
я использую более эффективный и идиоматический (cons X Y)
. Результат этой операции cons
должен быть передан в foo
. Аргумент out
- это наш аккумулятор, который пропускается через хвостовую рекурсию;он содержит сколько у нас пока списка.
Т.е. у нас не может быть (progn <make-new-list> (foo ... <old-list>))
;он просто создает новый список и выбрасывает его, а затем просто передает старый список рекурсивному вызову. Поскольку старый список изначально имеет вид nil
, мы просто продолжаем передавать это nil
, и когда индекс достигает нуля, это то, что выскакивает. Нам нужно (foo .... <make-new-list>)
, что я и сделал.
Тесты:
[1]> (foo "" -1 nil)
NIL
[2]> (foo "a" 0 nil)
(|a|)
[3]> (foo "ab" 1 nil)
(|a| |b|)
[4]> (foo "abcd" 3 nil)
(|a| |b| |c| |d|)
[5]> (foo "abcd" 3 '(x y z))
(|a| |b| |c| |d| X Y Z)
Наконец, если вы хотите, чтобы символы (|a| |b| |c| |d|)
выглядели как (a b c d)
, у вас естьвозиться с readtable-case
.
Конечно:
[6]> (foo "ABCD" 3 nil)
(A B C D)