Création d'une bibliothèque de fonctions pour muter les variables mondiales arbitraires

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

  •  25-08-2022
  •  | 
  •  

Question

MISE À JOUR: Si j'ai quelques fonctions que je veux muter une variable globale qui est transmise comme un argument de fonction, certains peuvent le faire en passant uniquement le symbole du global (comme dans le cas de pousser quelque chose sur une partie d'une liste) , mais d'autres fonctions nécessiteront que le symbole soit cité lorsqu'il est passé afin que je puisse accéder à la valeur de symbole et muter la variable extérieure, requise pour utiliser SETQ dans une fonction. Cette question concerne essentiellement la création d'une interface cohérente pour un utilisateur de ces fonctions sans les confondre que parfois vous passez le symbole, autre fois, vous passez le symbole cité

Exemple de façon de rationaliser l'interface pour un tas de fonctions, en utilisant un aide qui a le même utilisation sans rapport sur le fonctionnement de la fonction de mutation:

Voici 2 exemples de base de ma technique:

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

Dans ce dernier, je dois eval la global Puisqu'il est cité pour une utilisation avec symbol-value et puis je copy-list pour que global n'est pas directement muté accidentellement par n'importe quoi fn Je choisis (comme cela serait le cas avec push-cdr qui pourrait être non trivial dans des fonctions plus compliquées).

Production:

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)

... et les mêmes fonctions pourraient être utilisées avec *g1* ou *g3* etc tout au long de la fonction d'accès set-global.

Est-ce bon ou mauvais style, ou est-ce que je manque une bien meilleure façon d'atteindre cette fonctionnalité?

Était-ce utile?

La solution 2

Pourquoi ne vous débarrassez pas set-global fonction entièrement, et si vous voulez que toute votre fonction ait le même style de passage dans la variable globale, faites-les utiliser tous symbol-value Ainsi, toute personne qui utilise ces fonctions n'aura pas besoin de savoir ce qui fait et qui ne nécessite pas de devis devant le nom de variable global qui se fait passer. Beaucoup plus facile, non?

Autres conseils

C'est un mauvais style et une perte de temps.

  1. push-something est équivalent à cons.

  2. push-cdr est ne pas fonctionnel: il modifie l'argument en place ou échoue avec une erreur sur nil dispute.

Si vous souhaitez modifier la valeur de la variable globale, alors en utilisant setf Explicitement est beaucoup plus clair.

Si vous souhaitez modifier les internes d'une valeur globale d'une manière complexe, vous devrez peut-être rédiger une fonction spéciale pour cela - mais cette fonction devrait être agnostique du fait qu'il modifie la valeur liée à une variable globale par opposition à une variable lexicale.

En bref, il existe deux problèmes orthogonaux distincts - modifiant une variable globale (utilisez setq) et changer les internes d'un objet (être agnostique de sa nature mondiale).

Ps. Je ne sais pas ce que vous entendez par "Setf ne modifie pas la valeur d'une variable globale lorsqu'elle est à l'intérieur de la fonction", mais:

(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top