Erstellen einer Bibliothek von Funktionen, um willkürliche globale Variablen zu mutieren

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

  •  25-08-2022
  •  | 
  •  

Frage

UPDATE: Wenn ich einige Funktionen habe, die ich eine globale Variable mutieren möchte, die als Funktionsargument übergeben wird, können einige dies tun, indem ich nur das Symbol des Globalen übergeben kann (wie im Fall, dass etwas auf einen Teil einer Liste drückt) Aber andere Funktionen erfordern, dass das Symbol zitiert wird, wenn es übergeben wird, damit ich auf den Symbolwert zugreifen und die äußere Variable mutieren kann, die für die Verwendung von SETQ in einer Funktion erforderlich ist. Bei dieser Frage geht es im Grunde genommen darum, eine konsistente Schnittstelle für einen Benutzer dieser Funktionen zu erstellen, ohne sie zu verwirren, dass Sie manchmal das Symbol übergeben, andere Sie über das zitierte Symbol bestehen

Beispielweise, um die Schnittstelle für eine Reihe von Funktionen zu optimieren, indem Sie einen Helfer verwenden, der dieselbe Verwendung hat, die sich nicht weist, wie die Mutationsfunktion funktioniert:

Hier sind 2 grundlegende Beispiele meiner Technik:

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

In diesem letzten muss ich eval das global Da wird es für die Verwendung mit zitiert symbol-value und dann habe ich copy-list so dass global ist nicht direkt von versehentlich durch was auch immer mutiert fn Ich wähle (wie es bei der Fall ist push-cdr was bei komplizierteren Funktionen nicht trivial sein könnte).

Ausgabe:

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)

... und die gleichen Funktionen könnten mit verwendet werden *g1* oder *g3* uswig über die Zugriffsfunktion set-global.

Ist dieser gute oder schlechte Stil oder fehlt mir ein viel besserer Weg, um diese Funktionalität zu erreichen?

War es hilfreich?

Lösung 2

Warum wirst du nicht los? set-global Funktion vollständig und wenn Sie möchten, dass alle Ihre Funktionen den gleichen Bestehen der globalen Variablen haben, lassen Sie sie einfach alle verwendet symbol-value Jeder, der diese Funktionen nutzt, muss also nicht wissen, welche tun und welche kein Angebot vor dem globalen Variablennamen benötigt, der übergeben wird. Viel einfacher richtig?

Andere Tipps

Dies ist ein schlechter Stil und eine Zeitverschwendung.

  1. push-something ist äquivalent zu cons.

  2. push-cdr ist nicht Funktional: Es verändert das Argument an Ort nil Streit.

Wenn Sie den Wert der globalen Variablen ändern möchten, verwenden Sie dann setf explizit ist viel klarer.

Wenn Sie die Interna eines globalen Wertes auf komplizierte Weise ändern möchten, müssen Sie möglicherweise eine spezielle Funktion dafür schreiben - diese Funktion sollte jedoch agnostisch sein, dass sie den an eine globalen Variablen gebundenen Wert im Gegensatz zu der Tatsache ändern, dass sie im Gegensatz zu einer globalen Variablen ändert eine lexikalische Variable.

Kurz gesagt, es gibt zwei separate orthogonale Probleme - eine globale Variable ändern (Verwendung setq) und sich verändernde Interna eines Objekts (agnostisch seiner globalen Natur).

Ps. Ich bin mir nicht sicher, was Sie unter "SETF ändert den Wert einer globalen Variablen nicht, wenn sie in der Funktion ist", sondern:

(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top