¿Por qué no te deshaces de set-global
función por completo, y si desea que toda su función tenga el mismo estilo de pasar en la variable global, solo haga que todos usen symbol-value
Por lo tanto, cualquiera que use estas funciones no necesitará saber cuál y cuál no requiere una cotización frente al nombre de la variable global que se pasa. Mucho más fácil, ¿verdad?
Creación de una biblioteca de funciones para mutar variables globales arbitrarias
-
25-08-2022 - |
Pregunta
ACTUALIZACIÓN: Si tengo algunas funciones que quiero mutar una variable global que se pasa como argumento de una función, algunos pueden hacerlo pasando solo el símbolo de lo global (como en el caso de empujar algo a parte de una lista) , pero otras funciones requerirán que el símbolo se cita cuando se apruebe para que pueda acceder al valor del símbolo y mutar la variable externa, requerida para usar SETQ en una función. Esta pregunta es básicamente acerca de crear una interfaz consistente para un usuario de estas funciones sin confundirlas que a veces pases el símbolo, otras veces pasas el símbolo citado
Ejemplo de la forma de optimizar la interfaz para un montón de funciones, utilizando un ayudante que tiene el mismo uso sin requisitos de cómo funciona la función de mutación:
Aquí hay 2 ejemplos básicos de mi técnica:
(defun push-something (global something)
(push something global)
global) ;; not necessary to return it here since the
;; preceding line already does, but doing so
;; for consistency with other functions and clarity
(defun push-cdr (global something)
(push something (cdr global))
global) ;; must return it if I am going to set the
;; dynamic var to the result of this function,
;; because the preceding line doesn't return the
;; entire new result of the variable
;;; "dirty" function for mutating global variable using "clean" functions above:
(defun set-global (fn global &rest values)
(setf (symbol-value global) (apply fn (copy-list (eval global)) values)))
En este último, debo eval
la global
ya que se cita para su uso con symbol-value
y luego yo copy-list
de modo que global
no está directamente mutado accidentalmente por lo que sea fn
Elijo (como sería el caso con push-cdr
que podría ser no trivial en funciones más complicadas).
Producción:
CL-USER> (defparameter *g2* nil)
*G2*
CL-USER> (set-global #'push-something '*g2* 5)
(5)
CL-USER> *g2*
(5)
CL-USER> (set-global #'push-cdr '*g2* 99)
(5 99)
CL-USER> *g2*
(5 99)
... y las mismas funciones podrían usarse con *g1*
o *g3*
etc en toda la función de acceso set-global
.
¿Es este estilo bueno o malo, o me estoy perdiendo una manera mucho mejor de lograr esta funcionalidad?
Solución 2
Otros consejos
Este es un mal estilo y una pérdida de tiempo.
push-something
es equivalente acons
.push-cdr
es no funcional: modifica el argumento en el lugar o falla con un error ennil
argumento.
Si desea cambiar el valor de la variable global, entonces utilizando setf
Explícitamente es mucho más claro.
Si desea modificar las partes internas de un valor global de alguna manera compleja, es posible que deba escribir una función especial para eso, pero esa función debe ser agnóstica del hecho de que está modificando el valor vinculado a una variable global en lugar de una variable léxica.
En resumen, hay dos problemas ortogonales separados: cambiar una variable global (use setq
) y cambiar las partes internas de un objeto (sea agnóstico de su naturaleza global).
PD. No estoy seguro de lo que quiere decir con "SETF no cambia el valor de una variable global cuando está dentro de la función", pero::
(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123