Die skep van 'n biblioteek met funksies om arbitrêre globale veranderlikes te muteer

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

  •  25-08-2022
  •  | 
  •  

Vra

UPDATE: As ek 'n paar funksies het wat ek 'n wêreldwye veranderlike wil muteer wat as 'n funksie -argument oorgedra word, kan sommige dit doen deur net die simbool van die globale te gee (soos in die geval van iets op 'n deel van 'n lys) , maar ander funksies sal vereis dat die simbool aangehaal word wanneer dit geslaag word, sodat ek toegang tot die simboolwaarde kan kry en die buite-veranderlike kan muteer, wat benodig word vir die gebruik van setQ in 'n funksie. Hierdie vraag handel basies oor die skep van 'n konsekwente koppelvlak vir 'n gebruiker van hierdie funksies sonder om dit te verwar dat u soms die simbool deurgee, ander tye wat u deur die aangehaalde simbool slaag

Voorbeeld manier om die koppelvlak vir 'n klomp funksies te stroomlyn deur 'n helper te gebruik wat dieselfde gebruik het, is dit waarloos is van hoe die mutasie -funksie werk:

Hier is 2 basiese voorbeelde van my tegniek:

(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 hierdie laaste een moet ek eval die global Aangesien dit aangehaal word vir gebruik met symbol-value En dan ek copy-list sodat global word nie per ongeluk gemuteer deur wat ook al nie fn Ek kies (soos die geval sou wees met push-cdr wat in meer ingewikkelde funksies nie-triviaal kan wees).

Uitset:

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)

... en dieselfde funksies kon saam met *g1* of *g3* ens deur die toegangsfunksie set-global.

Is dit 'n goeie of slegte styl, of mis ek 'n baie beter manier om hierdie funksionaliteit te bereik?

Was dit nuttig?

Oplossing 2

Hoekom raak jy nie ontslae nie set-global funksioneer geheel en al, en as u wil hê dat al u funksie dieselfde styl in die globale veranderlike het, maak dit net om almal te gebruik symbol-value Enigiemand wat hierdie funksies gebruik, hoef dus nie te weet watter doen en wat nie 'n kwotasie benodig voor die wêreldwye veranderlike naam wat geslaag word nie. Baie makliker reg?

Ander wenke

Dit is 'n slegte styl en 'n vermorsing van u tyd.

  1. push-something is gelykstaande aan cons.

  2. push-cdr is nie Funksioneel: dit wysig die argument op die plek of misluk dit met 'n fout op nil argument.

As u die waarde van die globale veranderlike wil verander, gebruik dan setf eksplisiet is baie duideliker.

As u die internale van 'n globale waarde op 'n ingewikkelde manier wil verander, moet u miskien 'n spesiale funksie daarvoor skryf - maar die funksie moet agnosties wees van die feit dat dit die waarde verander wat gebind is aan 'n wêreldwye veranderlike in teenstelling met 'n leksikale veranderlike.

Kortom, daar is twee afsonderlike ortogonale probleme - die verandering van 'n wêreldwye veranderlike (gebruik setq) en veranderende interne van 'n voorwerp (wees agnosties van die wêreldwye aard daarvan).

PS. Ek is nie seker wat u bedoel met "SETF verander nie die waarde van 'n wêreldwye veranderlike as dit binne die funksie is nie", maar:

(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top