我在传递LISP中的结构组件时遇到问题。我想传递组件,而不是传递组件的值。
为了说明我的目标,假设我有一个结构实例node
。节点具有以下组件:farmer
,fox
,goose
和straw
。我希望该函数具有灵活性,因此可以将这些组件中的任何一个传递给函数。
(defun pass-comp (node object)
(setf object 1)
node)
(pass-comp (node (node-fox node))
(write (node-fox node))
—> 1
答案 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))