如何使用任意数量的args在lisp中定义结构?

Dav*_*egg 5 lisp structure common-lisp

我试图定义一个结构,其中包含我想知道的一些属性,以及基本结构不需要的任意数量的其他属性.

(defstruct (node (:type list)) label [other args here])
Run Code Online (Sandbox Code Playgroud)

我知道你可以在一个函数中做到:

(defun foo (arg1 &rest args) ...)
Run Code Online (Sandbox Code Playgroud)

有某种&rest等价物defstruct吗?

我只是在学习口齿不清,所以我有一种感觉,我错过了一些东西.如果没有&rest相应的,关于我如何去做这个的任何想法?提前致谢!

Rai*_*wig 7

在Common Lisp中,结构被认为是刚性和低级记录.他们没有花哨的动态功能.

你可以用结构做的是定义一个从另一个继承的新结构类型.有单一的继承可用.

要处理动态可扩展性,一种典型的方法是向结构添加属性列表槽.看约书亚的答案.

然后是Common Lisp Object System,它提供多重继承,您可以在运行时更改类.因此,您可以向类添加一个插槽,该类的实例会自行更新.您还可以更改对象的类,可以添加或删除插槽.但是,通常所有类的实例都将具有相同的插槽集.再次,可以看到可以添加具有属性列表的槽并用于可扩展性.

Common Lisp还有其他对象系统,可以轻松地在每个实例的基础上添加插槽.但通常使用它们通常太多了,因为它们的功能更强大.

使用CLOS和元对象协议,可以尝试隐藏它.在这里我使用LispWorks:

我们为我们的属性定义了一个mixin类:

(defclass property-mixin ()
  ((plist :initform nil))
  #+lispworks
  (:optimize-slot-access nil))
Run Code Online (Sandbox Code Playgroud)

设置和读取属性:

(defmethod set-property ((object property-mixin) key value)
  (setf (getf (slot-value object 'plist) key) value))

(defmethod get-property ((object property-mixin) key)
  (getf (slot-value object 'plist) key))
Run Code Online (Sandbox Code Playgroud)

现在我们编写方法来SLOT-VALUE接受我们的属性名称:

(defmethod (setf clos:slot-value-using-class)
       (value (class standard-class) (object property-mixin) slot-name)
  (declare (ignorable class)) 
  (if (slot-exists-p object slot-name)
      (call-next-method)
    (progn
      (set-property object slot-name value)
      value)))

(defmethod clos:slot-value-using-class ((class standard-class)
                                        (object property-mixin)
                                        slot-name)
  (declare (ignorable class))
  (if (slot-exists-p object slot-name)
      (call-next-method)
    (get-property object slot-name)))
Run Code Online (Sandbox Code Playgroud)

例.我们定义了一个有两个槽的汽车类:

(defclass automobile (property-mixin)
  ((company :initarg :company)
   (motor :initarg :motor))
  #+lispworks
  (:optimize-slot-access nil))
Run Code Online (Sandbox Code Playgroud)

现在是一个实例:

CL-USER 45 > (setf a6 (make-instance 'automobile :company :audi :motor :v6))
#<AUTOMOBILE 402005B47B>
Run Code Online (Sandbox Code Playgroud)

我们可以获得正常的插槽值:

CL-USER 46 > (slot-value c1 'motor)
:V6
Run Code Online (Sandbox Code Playgroud)

让我们写一个不存在的插槽,但是会添加到我们的属性列表中:

CL-USER 47 > (setf (slot-value a6 'seats) 4)
4
Run Code Online (Sandbox Code Playgroud)

我们可以获得价值:

CL-USER 48 > (slot-value c1 'seats)
4
Run Code Online (Sandbox Code Playgroud)


Jos*_*lor 6

目前尚不清楚您正在寻找什么.结构的默认情况是具有固定数量的槽的记录类型,每个槽都有一个名称,并且可以通过defstruct宏生成的函数访问.例如,一旦你完成了

(defstruct node 
  label)
Run Code Online (Sandbox Code Playgroud)

您可以访问node标签node-label并获得快速查找时间(因为它通常只是内存块的索引).现在,正如您所做的那样,您可以选择使用列表作为结构的实现,在这种情况下,node-label它只是car或的别名first.

(defstruct (node (:type list))
  label)

CL-USER> (make-node :label 'some-label)
(SOME-LABEL)
CL-USER> (node-label (make-node :label 'some-label))
SOME-LABEL
CL-USER> (first (make-node :label 'some-label))
SOME-LABEL
CL-USER> (car (make-node :label 'some-label))
Run Code Online (Sandbox Code Playgroud)

如果您正在寻找任意基于列表的键值对,您可能需要一个属性列表,Common Lisp包含一些便利函数.

如果您想拥有一个也包含属性列表的结构,您可以添加一个特殊的构造函数来填充该列表.例如,

(defstruct (node (:type list)
                 (:constructor make-node (label &rest plist)))
  label
  plist)

CL-USER> (make-node 'some-label :one 1 :two 2)
(SOME-LABEL (:ONE 1 :TWO 2))
CL-USER> (node-plist (make-node 'some-label :one 1 :two 2))
(:ONE 1 :TWO 2)
Run Code Online (Sandbox Code Playgroud)