Как мне рекурсивно добавить список в общий lisp? - PullRequest
0 голосов
/ 20 октября 2019
(defun foo (in i out)
    (if (>= i 0)
        (progn
            (append (list (intern (string (elt in i)))) out)
            (print output)
            (foo in (- i 1) out )
        )       
        (out)
    )
)

(print (foo "abcd" (- (length "abcd") 1) (list)))

Я пытаюсь вернуть эту строку как (abcd). Но он возвращает ноль в качестве вывода. Что я здесь не так делаю? Спасибо

Ответы [ 2 ]

2 голосов
/ 21 октября 2019

Я не знаю, какое это имеет отношение к добавлению. Я думаю, что ваш желаемый результат также странный, и вы не должны делать то, что вы делаете. Правильный объект для персонажа - это символ, а не символ. Тем не менее, хороший способ получить список (a b c d) выглядит следующим образом:

CL-USER> '(a b c d)

Символы вставки во время выполнения странные, поэтому, возможно, вам понравится:

(defconstant +alphabet+ #(a b c d e f g h i j k l m n o p q r s t u v w x y z))

(defun foo (seq)
  (map 'list
       (lambda (char)
          (let ((index (- (char-code char) (char-code #\a))))
            (if (< -1 index (length +alphabet+))
                (svref +alphabet+ index)
                (error "not in alphabet: ~c" char))))
       seq))
1 голос
/ 21 октября 2019

У вас есть только незначительные ошибки. Сначала нам нужно избавиться от 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)
...