如何在通用Lisp中递归地添加列表?

时间:2019-10-20 10:25:19

标签: lisp common-lisp

(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)))

我试图将此字符串返回为(a b c d)。但是它确实返回nil作为输出。我在这里做什么错?谢谢

2 个答案:

答案 0 :(得分:2)

我不知道这与追加有什么关系。我认为您想要的输出也很奇怪,因此您不应该执行自己的操作。字符的正确对象是字符而不是符号。不过,获取列表(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 :(得分:1)

您只有一些小错误。首先,我们需要摆脱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操作的结果必须传递到fooout参数是我们的累加器,它通过尾部递归进行处理;它保存了我们到目前为止有多少个列表。

即我们不能拥有(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)