使用实习生时如何在结构的访问器上执行setf

ait*_*zos 5 lisp common-lisp allegro-cl

我想setf根据某个变量来选择结构的不同字段。我决定使用以下方法:

生成一个带有字段访问者名称的字符串:

(setq my-string (format nil "STRUCT-ESTADISTICAS-NUM-~S" x))
Run Code Online (Sandbox Code Playgroud)

然后将intern与funcall一起使用:

(funcall (intern my-string) *estadisticas*)
Run Code Online (Sandbox Code Playgroud)

该调用返回结构字段的正确值,但是如果我尝试setf修改此值,它会抱怨说:

(setf (funcall(intern my-string) *estadisticas*) 0)
Error: `(SETF FUNCALL)' is not fbound
Run Code Online (Sandbox Code Playgroud)

我可以理解为什么它不起作用,但是我找不到修改结构域的方法。任何的想法?谢谢。

hua*_*uan 5

您想通过其名称调用该结构的writer函数,而writer的名称为list (setf accessor-name);所以

(funcall (fdefinition (list 'setf (intern my-string))) 0 estadisticas)
Run Code Online (Sandbox Code Playgroud)

编辑:

没有看到其余的代码,很难弄清出了什么问题。在SBCL上,这对我有用:

(defstruct point x y)
(let ((point (make-point :x 1 :y 2)))
  (funcall (fdefinition (list 'setf (intern "POINT-X"))) 10 point)
  point)
Run Code Online (Sandbox Code Playgroud)

以上评估为

#S(POINT :X 10 :Y 2),
Run Code Online (Sandbox Code Playgroud)

如预期的那样。

  • 我会说这是非标准的。不需要DEFSTRUCT来定义WRITER函数。 (2认同)

Rai*_*wig 5

动机:

结构是一个相对较低级别的工具。“速度”是重要的设计目标。该标准不支持通过writer函数进行间接寻址(在我阅读本文时)。如今,除非需要更高的结构效率(有时可以更快地读取和写入具有结构的插槽),否则将CLOS用作默认值。

第一-风格:

不要使用INTERN,请使用FIND-SYMBOL。还指定软件包,否则FIND-SYMBOL将使用* package *的运行时值作为软件包

第二-DEFSTRUCT

如果我正确地阅读了ANSI CL标准,那不是DEFSTRUCT像DEFCLASS那样为插槽创建写程序功能。

CL-USER 24 > (defstruct foo bar baz)
FOO

CL-USER 25 > #'(setf foo-bar)

Error: Undefined function (SETF FOO-BAR) in form (FUNCTION (SETF FOO-BAR)).
Run Code Online (Sandbox Code Playgroud)

因此,构造这样的名称(SETF FOO-BAR)并尝试为此找到一个函数将失败,因为DEFSTRUCT没有定义这样的函数。

用户代码(setf(foo-bar some-struct)42)的工作原理是基于DEFSTRUCT提供的定义的SETF扩展,而不是基于定义的SETF访问器函数。

一些Common Lisp实现可能提供编写器功能,作为ANSI CL的非标准扩展。

可能的解决方案

a)使用CLOS类,DEFCLASS可以满足您的要求

b)自己编写作家函数

(defun (setf foo-bar) (new-value struct)
   (setf (foo-bar struct) new-value))
Run Code Online (Sandbox Code Playgroud)

现在:

(funcall (fdefinition '(setf foo-bar)) 300 *foo*)
Run Code Online (Sandbox Code Playgroud)

以上然后工作。

c)(SETF SLOT-VALUE)-一些实现的另一个非标准功能。

在Common Lisp的某些实现中,这不仅适用于CLOS类,而且适用于结构:

(setf (slot-value some-struct 'bar) 42)
Run Code Online (Sandbox Code Playgroud)

我不确定Allegro CL是否支持这一点,但这很容易发现。