(defparameter *number-of-processes* 10)
(defvar *world* (make-world)) ; the world is made only once.
Zauważ, że prawdopodobnie nigdy nie chcą DEFVAR
zmiennych o nazwach takich jak x
, y
, stream
, limit
... Dlaczego? Ponieważ te zmienne zostaną uznane za specjalne i trudno je cofnąć. Specjalna deklaracja ma charakter globalny, a wszystkie dalsze zastosowania tej zmiennej wykorzystywałyby wiązanie dynamiczne.
BAD:
(defvar x 10) ; global special variable X, naming convention violated
(defvar y 20) ; global special variable Y, naming convention violated
(defun foo()
(+ x y)) ; refers to special variables X and y
(defun bar (x y) ; OOPS!! X and Y are special variables
; even though they are parameters of a function!
(+ (foo) x y))
(bar 5 7) ; -> 24
lepiej: oznaczyć zawsze zmienne specjalne *
w nazwie!
(defvar *x* 10) ; global special variable *X*
(defvar *y* 20) ; global special variable *Y*
(defun foo()
(+ *x* *y*)) ; refers to special variables X and y
(defun bar (x y) ; Yep! X and Y are lexical variables
(+ (foo) x y))
(bar 5 7) ; -> 42
Zmienne lokalne są wprowadzane z DEFUN, LAMBDA, LET, MULTIPLE-VALUE-BIND i wielu innych.
(defun foo (i-am-a-local-variable)
(print i-am-a-local-variable))
(let ((i-am-also-a-local-variable 'hehe))
(print i-am-also-a-local-variable))
Teraz domyślnie lokalne zmienne w dwóch powyższych form są leksykalny, chyba że są one zadeklarowane SPECIAL. Wtedy byłyby zmiennymi dynamicznymi.
Następnie istnieje również kilka formularzy do ustawienia zmiennej na nowe wartości.SET, SETQ, SETF i inne. SETQ
i SETF
można ustawić zarówno zmienne leksykalne, jak i specjalne (dynamiczne).
Wymagany jest dla przenośnego kodu, który ustawia zmienne, które są już zadeklarowane. Dokładny efekt ustawienia zmiennej nie zadeklarowanej jest niezdefiniowany przez standard.
Tak więc, jeśli wiesz, co robi twój Wspólna realizacja Lisp, można użyć
(setq world (make-new-world))
w odczytu-analizy-Print-Loop na Toplevel. Ale nie używaj go w swoim kodzie, ponieważ efekt nie jest przenośny. Zazwyczaj SETQ
ustawi zmienną. Ale niektóre implementacje mogą również zadeklarować zmienną SPECIAL, gdy jej nie zna (CMU Common Lisp robi to domyślnie). To prawie zawsze nie jest to, czego byśmy chcieli. Użyj go do swobodnego użytku, jeśli wiesz, co robisz, ale nie kodu.
samo tutaj:
(defun make-shiny-new-world()
(setq world (make-world 'shiny)))
Po pierwsze, takie zmienne powinny być zapisane jako *world*
(z otaczającymi *
znaków), aby wyjaśnić, że jest to specjalna zmienna globalna. Po drugie, powinno być zadeklarowane wcześniej: DEFVAR
lub DEFPARAMETER
.
Typowy kompilator Lisp będzie narzekał, że powyższa zmienna jest niezadeklarowana. Ponieważ globalne zmienne leksykalne nie istnieją w Common Lisp, kompilator musi wygenerować kod do dynamicznego wyszukiwania. Jakiś kompilator mówi, ok, zakładamy, że jest to dynamiczne wyszukiwanie, zadeklarujmy, że jest to specjalne - ponieważ to jest to, co i tak zakładamy.
Jestem zaskoczony, że po zadeklarowaniu zmiennej jako globalnej z defvar, nie ma możliwości, aby utworzyć lokalną zmienną o tej samej nazwie, więc (let ((x 1) x) może powodować nieoczekiwane wyniki, jeśli x jest deklarowane przez defvar. – Ian
@ian To jeden z powodów, dla którego wiele osób używa "nauszników" (to znaczy, że nigdy nie używają '(defvar x foo)', używają '(defvar * x * foo)', w ten sposób znacznie mniej prawdopodobne, aby zrobić błąd. – Vatine