2

我有一个在循环中使用的列表,并且在每次迭代中,我都会应用一个永久更改列表的函数(弹出和添加元素)。问题是,只要原始列表为零,就永远不会更改。我该如何解决这个问题?我的代码如下所示

(defun looping-func ()
    (let ((queue '(2)))
          (loop while (not (null queue)) do
            (let (  (num (pop queue)))
                (if (oddp num)
                    (format t "~%~A success" num)
                    (progn (format t "~%fail")
                           (add-to-list (1+ num) queue)))))))

(defun add-to-list (elem l)
    (nconc l (list elem)))

如果列表包含超过 1 个元素,则代码将按预期工作。如果它恰好包含 1 个元素,则一旦弹出该元素并且列表变为 nil,则应用的更改不再对列表永久存在。我想这是因为 nconc 是如何定义的,如果第一个参数为零,则只返回第二个参数而不做任何更改。关于如何解决这个问题的任何想法?

PS:我知道上面的代码没用,但是我在一个学校项目中使用了相同的概念,很遗憾我无法发布代码。

4

3 回答 3

3

改变

(add-to-list (1+ num) queue)

(setq queue (add-to-list (1+ num) queue))

你不能“扩展nilnconc

(nconc nil . lists)

相当于

(nconc . lists)

add-to-list所以,你需要把结果queue

于 2012-10-19T03:02:48.867 回答
3

不要将元素添加到列表的末尾。

绝不。

Lisp 中的列表的设计方式是向头部添加元素很便宜。添加到最后可能是昂贵的。

要实现 LIFO 队列,您需要不同的实现。

不要在运行时更改源代码中的常量文字数据。

正确缩进你的代码。

于 2012-10-20T08:53:05.957 回答
1

因为我认为这是一个练习,所以这里有一个例子,你不应该在日常练习中使用它,你应该使用push宏,它可能会做类似的事情:

(defmacro push-example (item list)
  (let ((the-list list))                ; we do this to prevent
                                        ; multiple evaluations
                                        ; of the `list' argument
  `(setq ,the-list (cons ,item ,the-list))))

(defparameter *test* nil)

(push-example 'foo *test*) ;; (foo)
*test* ;; (foo)

虽然您没有要求宏(您要求函数),但 Doug 的回答在技术上更正确,这说明了如何通过宏使用代码生成来完成它。请注意,这基本上与您的函数所做的事情相同,只是它可以封装对setq您必须进行的调用。

于 2012-10-19T10:13:36.357 回答