¿Cómo puedo hacer setf en descriptores de acceso de una estructura cuando se utiliza en prácticas

StackOverflow https://stackoverflow.com/questions/3641509

  •  30-09-2019
  •  | 
  •  

Pregunta

Me gustaría setf diferentes campos de una estructura en función de una determinada variable. Decidí usar el siguiente enfoque:

generar una cadena con el nombre de acceso del campo:

(setq my-string (format nil "STRUCT-ESTADISTICAS-NUM-~S" x))

y luego uso pasante con funcall:

(funcall (intern my-string) *estadisticas*)

Esta llamada devuelve el valor correcto del campo de la estructura, pero si intento setf modificar este valor se queja diciendo:

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

puedo entender por qué no funciona, pero no puedo encontrar una manera de modificar los campos de la estructura. ¿Alguna idea? Gracias.

¿Fue útil?

Solución

¿Quieres llamar a una función escritor de la estructura a través de su nombre, y el nombre del escritor es la lista (setf accessor-name); así

(funcall (fdefinition (list 'setf (intern my-string))) 0 estadisticas)

Editar:

No ver el resto de su código, que es difícil de entender lo que salió mal. En SBCL esto funciona para mí:

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

Las evalúa arriba para

#S(POINT :X 10 :Y 2),

como se esperaba.

Otros consejos

de motivación:

Las estructuras son una instalación relativamente bajo nivel. 'Velocidad' era un objetivo importante del diseño. Indirecto a través de funciones escritor no es compatible con el estándar (como lo leí). Hoy en día, el uso CLOS como el valor por defecto, a menos que las necesidades de una mejor eficacia de las estructuras (más rápido leen y son a veces posible escrituras de ranuras con estructuras).

Primera - estilo:

No consumo interno, el uso FIND-símbolo. También debe especificar el paquete, de lo contrario FIND-SÍMBOLO utilizará el valor de tiempo de ejecución del paquete * * como el paquete

Segundo - defstruct

Si leo el estándar ANSI CL correctamente, no es que crea defstruct funciones escritor de ranuras como DEFCLASS hace.

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)).

Por lo tanto, la construcción de un nombre (SETF foo-bar) y tratando de encontrar una función para la que se producirá un error, ya que no existe tal función definida por el defstruct.

Que en código de usuario (setf (foo-BAR algunos-struct) 42) funciona, se basa en las expansiones setf definidos proporcionados por defstruct, pero no en SETF definido de acceso funciones.

Algunas implementaciones de Common Lisp puede proporcionar funciones de escritor como una extensión no estándar ANSI CL.

Posibles soluciones

a) las clases de uso Clos, DEFCLASS hace lo que quiere

b) escribir las funciones escritor mismo

(defun (setf foo-bar) (new-value struct)
   (setf (foo-bar struct) new-value))

Ahora:

(funcall (fdefinition '(setf foo-bar)) 300 *foo*)

Por encima de entonces funciona.

c) (SETF SLOT-VALUE) -. Otra característica no estándar de algunas implementaciones

En algunas implementaciones de Common Lisp esto funciona no sólo para las clases de CLOS, sino también para las estructuras:

(setf (slot-value some-struct 'bar) 42)

No estoy seguro de si Allegro CL hace que el apoyo, pero que sería fácil de averiguar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top