为什么下面的 lisp 代码没有给出预期的结果

Why the below lisp code is not giving desired result

我有一个列表

'((1 2 (A B C)) (2 3 (B C D)) (4 5 (C D F)))

我想处理内部列表中的元素,(在这种情况下,我想将(A B C)和其他列表更改为(M M M))。

我写了一个代码(process lst),它将为内部列表完成这个任务。

(defun process (lst)
  (cond
    ((null lst) '())
    (T (cons 'M (process (cdr last))))))

当我从主函数调用时,

(defun iterate-list (lst)
  (cond
    ((null lst) '())
    ((listp (car lst)) 
     (cons (process (car lst)) 
           (iterate-list (cdr lst))))
    (T 
     (cons (car lst) 
           (iterate-list (cdr lst))))))

我得到的是 ((M M M) (M M M) (M M M)) 而不是 ((1 2 (M M M)) (2 3 (M M M)) (4 5 (M M M)))

但是当我使用相同的函数时,在第二个条件 (listp (car lst)) 中只有 (cons (car lst)) (iterate-list (cdr lst))),我得到了正确的答案,即

'((1 2 (A B C)) (2 3 (B C D)) (4 5 (C D F)))

我不知道我哪里错了。

如果你想要一些实用的东西,我建议使用 Common LISP Standard Library 中的 subst 函数。

http://clhs.lisp.se/Body/f_substc.htm

(setq tree1 '(1 (1 2) (1 2 3) (1 2 3 4))) =>  (1 (1 2) (1 2 3) (1 2 3 4))
(subst "two" 2 tree1) =>  (1 (1 "two") (1 "two" 3) (1 "two" 3 4))
(subst "five" 5 tree1) =>  (1 (1 2) (1 2 3) (1 2 3 4))

您还可以通过使用带有 lambda 函数的变体 subst-if 添加您自己的相等函数。

注意。您需要在 process.

中将 last 重命名为 lst

I am getting ((M M M) (M M M) (M M M)) instead of ((1 2 (M M M)) (2 3 (M M M)) (4 5 (M M M))).

代码有效,但不是您想要的深度:

(process '(a b c d))
=> (M M M M)

(iterate-list '(1 2 (A B C)))
=> (1 2 (M M M))

为了处理根列表中的所有列表,您可以这样做:

(mapcar #'iterate-list '((1 2 (A B C))
                         (2 3 (B C D))
                         (4 5 (C D F))))

=> ((1 2 (M M M)) (2 3 (M M M)) (4 5 (M M M)))