Common Lisp,列表处理(附加等)

时间:2017-06-06 01:17:51

标签: lisp common-lisp

我必须处理这种情况:

(defun make-point (a b)
(cons a b))

此函数在笛卡尔轴上创建一个点(为方便起见,我省略了通用控件)。我怎样才能实现一个函数,每次调用make点时,它都会更新一个列出所有点都附加的列表?

E.g。

'()
((1.1))
((1.1)(2.4))
((1.1)(2.4)(4.5))

我需要将列表作为以下函数的参数。

1 个答案:

答案 0 :(得分:2)

您定义一个变量:

(defvar *points* '())

变量名称周围的星号(称为"耳罩")是CL中非常强大的约定,表示声明为特殊的变量,就是这种情况使用DEFVAR/DEFPARAMETER时。我在这里使用DEFVAR,因为如果我需要重新加载代码所在的编译单元,我不希望将点列表重置为空列表。

然后,您可以为程序员提供一个界面来抽象该点列表:

(defun clear-all-points ()
  (setf *points* nil))

(defun add-point (point)
  (push point *points*))

在这里你可以看到我将给定点存储在点列表的前面,这是使用列表的自然方式;最后附加的东西,要求你遍历列表,这在大多数情况下是浪费的,没有必要。此外,如何追加新元素可能会改变点列表的使用方式:

  • 如果您将add-point实施为

    (setf *points* (append *points* (list point)))
    

    ...然后*points*引用的列表是一个副本,如果您之前将*points*存储在另一个地方,那么您现在有两个点列表(我不是说这是正确的或错在这里,只是解释会发生什么);

  • 但是,如果您改变列表:

    (setf *points* (nconc *points* (list point)))
    

    ...然后你可以在不同的对象之间共享列表,每当他们阅读列表时,他们都会得到所有点的最新列表。

您可能还需要考虑使用这两种方法将使用多少内存。如果通过复制附加APPEND,则前一个列表最终将被垃圾收集器回收;如果过于频繁地添加点数,您将开始以一种可能降低性能的方式来丢弃内存。

如果你需要把事情放在最后而不诉诸NCONC考虑​​使用队列或数组。  基本队列可以简单地在列表顶部,通过队列对象实现,该队列对象只是一个构成单元,其中car是基础列表的第一个单元格和{{ 1}}是同一列表中的 last 缺点单元格。将元素cdr追加到列表x时,您将从此状态开始:

(e0 ... en)

...到这个

( e0 . ( ...  (en . nil) ... ))
^first        ^last

您可以尝试将其作为另一项练习来实施。

然后,你可以保持你的功能不受影响(但缩进);你可能不必在没有将它们添加到全局列表中的情况下制作点数,因此将事物分开是有意义的:

( e0 . ( ...  (en . (x . nil)) ... ))
^first              ^last

如果需要,可以定义一个结合两种动作的辅助功能:

(defun make-point (a b)
  (cons a b))

另外,请注意空格很重要:您在所需输出中写的内容(例如(defun add-new-point (a b) (add-point (make-point a b))) )是浮点数列表。

相关问题