在Lisp中分配

时间:2015-10-17 14:59:46

标签: lisp common-lisp assign

我在Common Lisp中有以下设置。 my-object是5个二叉树的列表。

(defun make-my-object ()
    (loop for i from 0 to 5
          for nde = (init-tree)
          collect nde))

每个二叉树都是大小为3的列表,其中包含node,左子项和右子项

(defstruct node
    (min 0)
    (max 0)
    (ctr 0))

(defun vals (tree)
    (car tree))

(defun left-branch (tree)
    (cadr tree))

(defun right-branch (tree)
    (caddr tree))

(defun make-tree (vals left right)
    (list vals left right))

(defun init-tree (&key (min 0) (max 1))
    (let ((n (make-node :min min :max max)))
        (make-tree n '() '())))

现在,我试图手动将一个元素添加到其中一个二叉树中,如下所示:

(defparameter my-object (make-my-object))
(print (left-branch (car my-object))) ;; returns NIL
(let ((x (left-branch (car my-object))))
    (setf x (cons (init-tree) x)))
(print (left-branch (car my-object))) ;; still returns NIL

print的第二次调用仍会返回NIL。为什么是这样?如何在二叉树中添加元素?

2 个答案:

答案 0 :(得分:4)

第一个功能就是:

(defun make-my-object ()
  (loop repeat 5 collect (init-tree)))

现在您为node定义了一个结构,但是您使用 my-object 的列表?为什么他们没有结构?

而不是carcadrcaddr可以使用firstsecondthird

(let ((x (left-branch (car my-object))))
   (setf x (cons (init-tree) x)))

您将局部变量x设置为新值。为什么?在let之后,局部变量也消失了。为什么不设置左分支呢?您需要定义一种方法。请记住:Lisp函数返回值,而不是您稍后可以设置的内存位置。如何更改列表中的内容?更好的是:使用结构并更改槽值。结构(甚至CLOS类)优于普通列表:对象带有类型,槽名称,创建访问器,创建make函数,创建类型谓词,...

无论如何,我会为node,tree和 object 定义结构或CLOS类......

答案 1 :(得分:2)

此问题中的大多数代码对于此处的实际问题并不重要。真正的问题在于对这段代码的误解:

(let ((x (left-branch (car my-object))))
  (setf x (cons (init-tree) x)))

如果没有任何类型的用户定义结构,我们可以看到相同的行为:

(let ((cell (cons 1 2)))
  (print cell)            ; prints (1 . 2)
  (let ((x (car cell)))
    (setf x 3)
    (print cell)))        ; prints (1 . 2)

如果您理解为什么两个印刷语句都会生成(1.2),那么您已经足够理解为什么您自己的代码不会执行您(之前)预期的操作它要做。

这里有两个变量:单元格 x 。有三个值我们关注 1 2 ,以及通过调用(cons 1 2)生成的cons-cell 。 Lisp中的变量通常称为绑定;变量或名称​​绑定到一个值。变量 cell 绑定到cons单元(1.2)。当我们进入内部let时,我们评估(car cell)以产生值 1 ,然后绑定到变量 X 即可。然后,我们为变量 x 分配一个新值 3 。这并不会修改包含 x 最初绑定的值的cons单元格。实际上,最初绑定到 x 的值是由(汽车单元格)生成的,一旦返回(汽车单元格)的调用,重要的唯一值是 1

如果您有其他编程语言方面的经验,这与

类似
int[] array = ...;
int x = array[2];    // read from the array; assign result to x
x = 42;              // doesn't modify the array

如果要修改结构,则需要 setf 结构的相应部分。 E.g:

(let ((cell (cons 1 2)))
  (print cell)            ; prints (1 . 2)
  (setf (car cell) 3)
  (print cell))           ; prints (3 . 2)