LISP-传递结构组件,而不是组件的值

时间:2018-10-14 02:55:40

标签: lisp common-lisp

我在传递LISP中的结构组件时遇到问题。我想传递组件,而不是传递组件的值。

为了说明我的目标,假设我有一个结构实例node。节点具有以下组件:farmerfoxgoosestraw。我希望该函数具有灵活性,因此可以将这些组件中的任何一个传递给函数。

(defun pass-comp (node object)
  (setf object 1)
  node)

(pass-comp (node (node-fox node))
(write (node-fox node))
—> 1

2 个答案:

答案 0 :(得分:4)

在Lisp中,所有参数始终按值传递。 如果要修改传递的结构的内容,可以通过指定要修改的内容来完成:

(defstruct node farmer fox goose straw)
(defparameter *node* (make-node :fox 3))
(defun change-slot (object slot-name new-value)
  (setf (slot-value object slot-name) new-value))
(change-slot *node* 'fox 7)
(change-slot *node* 'goose 23)
*node*
==> #S(NODE :FARMER NIL :FOX 3 :GOOSE 23 :STRAW NIL)

请注意,即使该标准不需要 slot-value继续工作 structure-object, 上面的代码适用于所有CL实现。

如果您希望代码为conforming,则应通过设置器

(defun change-slot (object setter new-value)
  (funcall setter new-value object))
(change-slot *node* #'(setf node-farmer) 6)
*node*
==> #S(NODE :FARMER 6 :FOX 3 :GOOSE 23 :STRAW NIL)

a,这because也不保证能起作用:

  

写插槽的功能是由setf函数还是由setf扩展器实现取决于实现。

因此,您需要创建自己的设置器:

(change-slot *node* (lambda (straw node) (setf (node-straw node) straw)) 11)
*node*
==> #S(NODE :FARMER 6 :FOX 3 :GOOSE 23 :STRAW 11)

答案 1 :(得分:2)

结构在标准CL中非常静态-例如,重新定义结构的效果是不确定的。如果我们可以通过插槽名称访问结构,则也是未定义的。现有的是插槽读取器功能,以及将其与setf配合使用的支持。

假设我们有一个结构类型:

(defstruct node fox)

然后,当我们要更改结构的组件时,我们需要传递一个用于设置该组件的函数:

(defun pass-comp (node setter-fn)
  (funcall setter-fn node 1)
  node)

然后我们可以传递一个setter函数:

(let ((my-node (make-node)))
  (pass-comp my-node
             (lambda (node new)
               (setf (node-fox node) new)))
  (node-fox my-node))