Существует несколько способов ввода переменных.
DEFVAR и DEFPARAMETER вводят глобальные динамические переменные. DEFVAR
опционально устанавливает его в какое-либо значение, если оно уже не определено. DEFPARAMETER
всегда устанавливает указанное значение.
SETQ не вводит переменную.
(defparameter *number-of-processes* 10)
(defvar *world* (make-world)) ; the world is made only once.
Обратите внимание, что вы, вероятно, никогда не захотите DEFVAR
переменных с именами, такими как x
, y
, stream
, limit
, ... Почему? Потому что тогда эти переменные будут объявлены специальными, и это трудно отменить. Специальное объявление является глобальным, и при дальнейшем использовании переменной будет использоваться динамическое связывание.
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
ЛУЧШЕ: Всегда отмечайте специальные переменные с *
в их именах!
(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
Локальные переменные вводятся с DEFUN , LAMBDA , LET , MULTIPLE-VALUE-BIND и многими другими.
(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))
Теперь по умолчанию локальные переменные в двух вышеуказанных формах являются лексическими, если только они не объявлены SPECIAL . Тогда они будут динамическими переменными.
Далее, есть также несколько форм для установки переменной в новые значения. SET , SETQ , SETF и другие. SETQ
и SETF
могут устанавливать как лексические, так и специальные (динамические) переменные.
Для переносимого кода требуется, чтобы переменные уже были объявлены. Точный эффект установки необъявленной переменной не определен стандартом.
Итак, если вы знаете, что делает ваша реализация Common Lisp, вы можете использовать
(setq world (make-new-world))
в Read-Eval-Print-Loop на верхнем уровне. Но не используйте его в своем коде, так как эффект не переносимый. Обычно SETQ
устанавливает переменную. Но некоторые реализации могут также объявить переменную SPECIAL , когда она этого не знает (CMU Common Lisp делает это по умолчанию). Это почти всегда не то, что хотелось бы. Используйте его для повседневного использования, если вы знаете, что делаете, но не для кода.
То же самое здесь:
(defun make-shiny-new-world ()
(setq world (make-world 'shiny)))
Во-первых, такие переменные должны быть записаны как *world*
(с окружающими символами *
), чтобы было ясно, что это глобальная специальная переменная. Во-вторых, он должен был быть объявлен с DEFVAR
или DEFPARAMETER
раньше.
Типичный компилятор Lisp будет жаловаться, что указанная выше переменная не объявлена. Поскольку глобальные лексические переменные не существуют в Common Lisp, компилятор должен генерировать код для динамического поиска. Затем какой-то компилятор говорит: «Хорошо, мы предполагаем, что это динамический поиск, давайте объявим, что он special - поскольку это то, что мы предполагаем в любом случае.