我正在尝试将给定变量x
添加到列表L
。这两个都是函数ADDV
的参数。我到目前为止的代码如下:
(defun addV(L x)
(cond
((eq L nil) nil)
((eq (cdr L) nil) (list(+(car L) x)))
(+ x (first(last L)))
(butlast L)
(append L x) ) )
使用参数
L = '(1 2 3 4)
x = 2
评估语句(+ x (first(last L))))
时,其值为4
。最终目标应该是
L = '(1 2 3 6)
我不确定我做错了什么。任何帮助将不胜感激。谢谢。
答案 0 :(得分:2)
您的代码格式错误。重新缩进,我们得到
(defun addV(L x)
(cond
((eq L nil)
nil)
((eq (cdr L) nil)
(list (+ (car L) x)))
(+
x
(first (last L)))
(butlast
L)
(append
L
x) ) )
你现在看到问题吗?
由于(not +)
为NIL
,因此输入COND
表单中的相应子句。它的主体形式(x
和(first (last L))
)被评估效果,其中没有效果。然后返回最后一个表单的值。
你明显希望它是什么,是
(defun addV (L x)
(cond
((eq L nil)
nil)
((eq (cdr L) nil)
(list (+ (car L) x)))
(T
(append
(butlast L)
(list (+ x (first (last L))))))))
巧合的是,第二个条款完全没有必要,可以省略,使其成为
(defun addV (L x)
(if (not (null L))
(append (butlast L)
(list (+ x (first (last L)))))))
答案 1 :(得分:2)
如果您可以破坏性地执行此操作,那么您可以使用incf
和last
:
(defun increment-last (list x)
(prog1 list ; return the list
(incf (first (last list)) x)))
如果您确实需要制作新列表,则必须走到列表末尾才能到达最后一个元素。当你这样做时,你可以跟踪你已经看过的元素(按相反的顺序),并有效地使用反向顺序列表,使用nreconc
为你构建新的列表:
(defun plus-last (list x)
(do ((list list (rest list))
(rhead '() (list* (first list) rhead)))
((endp (rest list))
(nreconc rhead (list (+ x (first list)))))))
CL-USER> (plus-last '(1 2 3 4) 2)
(1 2 3 6)
如果你对do
语法不太满意,你也可以使用尾递归函数(一些Common Lisp实现可以优化到循环中):
(defun plus-last (list x)
(labels ((pl (list rhead)
(if (endp (rest list))
(nreconc rhead (list (+ x (first list))))
(pl (rest list)
(list* (first list) rhead)))))
(pl list '())))
您也可以使用loop
,并清楚地表达逻辑:
(defun plus-last (list x)
(loop for (a . b) on list
if (null b) collect (+ a x)
else collect a))
这也可以通过maplist
:
(defun plus-last (list x)
(maplist (lambda (list)
(if (endp (rest list))
(+ x (first list))
(first list)))
list))