Конструкция declare используется для встраивания деклараций внутрь выполняемого кода. Глобальные декларации и декларации, вычисленные программой, устанавливаются конструкцией proclaim.
Для установки глобальных деклараций часто бывает удобен макрос declaim, он в отличии от proclaim не вычисляет свои аргументы.
Форма declare известна как декларация. Декларации могут использоваться только в начале тел соответствующих специальных форм. То есть декларация может использоваться в этом оператора, как выражение, и все предыдущие выражение (если есть) также должны быть формами declare (или, в некоторых случаях, строками документации). Декларации могут использоваться в лямбда-выражениях и перечисленных ниже формах.
Вычисление декларации является ошибкой. Операторы, которые позволяют использовать декларации, явно проверяют их наличие.
Макровызовы могут раскрываться в декларации, при условии, что макровызов указан в том месте, где могут быть указаны декларации. (Однако, макровызов не может использоваться в форме declare на месте decl-spec.)
Декларация может использовать только явно в теле соответсвтующего специального оператора в виде списка, car которого равен символу declare.
Каждая форма decl-spec является списком, у которого car элемент это символ, указывающий на тип декларации. Декларации могут быть разделены на два класса: одни относятся к связыванию переменных, другие нет. (Декларация special является исключением, она попадает в оба класса, это будет описано ниже.) Те, которые касаются связываний переменных, применяются только к связываниям, созданным в форме, в которой они используются. Например, в
декларация type применяется только для внешнего связывания x, а не для связывания, созданного в let.
Декларации, которые не воздействуют на связывания переменных, воздействуют на весь код тела в оператора. Например,
рекомендует, что везде внутри тела функции foo, floor должна быть вызвана как отдельная подпрограмма, а не встроена в код.
Некоторые операторы содержат части кода, которые, правильнее говоря, не являются телом этого оператора. Это например код инициализации переменных и форма результата для циклов. Во всех случаях, такой дополнительный код оказывается под воздействием всеобъемлемых деклараций, которые указаны перед телом оператора. Невсеобъемлемые декларации не оказывают воздействия на этот код, за исключением (конечно) ситуаций, когда код находится в области действия переменной, для которой использовалась декларация. Например:
Ссылка на *print-circle* в первой строке примера является специальной, так как указана соответствующая декларация.
В этом примере, декларация inline применяется только ко второму и третьему вызову foo. Декларация special для переменной x указывает, что форма let создаст специальное связывание для x и тем самым ссылки в теле формы также будут специальными. Ссылка на x во втором вызове foo является специальной. Ссылка на x в первом вызове foo является локальной, а не специальной. Декларация special для z указывает на то, что ссылка в вызове foo будет специальной. Это значит ссылка не будет указывать на параметр функции nonsense, так как для параметра декларации special не указано. (Декларация special переменной z указывается не в теле defun, а в теле внутренней конструкции let. Таким образом она не воздействует на связывание параметра функции.)
Note that the distinction between pervasive and non-pervasive declarations is eliminated. An important change from the first edition is that “initialization” forms are specifically not included as part of the body under the first rule; on the other hand, in many cases initialization forms may fall within the scope of certain declarations under the second rule.
X3J13 also voted in January 1989 to change the interpretation of type declarations (see section 9.2).
These changes affect the interpretation of some of the examples from the first edition.
Under the interpretation approved by X3J13, the type declaration applies to both bindings of x. More accurately, the type declaration is considered to apply to variable references rather than bindings, and the type declaration refers to every reference in the body of foo to a variable named x, no matter to what binding it may refer.
This example of the use of notinline stands unchanged, but the following slight extension of it would change:
Under first edition rules, the notinline declaration would be considered to apply to the call to floor in the initialization form for y. Under the interpretation approved by X3J13, the notinline would not apply to that particular call to floor. Instead the user must write something like
or perhaps
Similarly, the special declaration in
is not considered to apply to the reference in the initialization form for y in few. As for the nonsense example,
under the interpretation approved by X3J13, the inline declaration is no longer considered to apply to the second call to foo, because it is in an initialization form, which is no longer considered in the scope of the declaration. Similarly, the reference to x in that second call to foo is no longer taken to be a special reference, but a local reference to the second parameter of nonsense.
locally выполняет формы form как неявный progn и возвращает одно или несколько значений последней формы.
Когда оператор locally используется на верхнем уровне, тогда формы в его теле выполняются как формы верхнего уровня. Это означает что, например, locally можно использовать для оборачивания деклараций вокруг форм defun или defmacro.
Без уверенности, что это работает, можно записать что-то вроде этого:
Функция proclaim в качестве аргумента принимает decl-spec, и применяет указания в глобальном пространстве. (Такие глобальные декларации называются прокламации.) Так как proclaim является функцией, то её аргумент вычисляется всегда. Это позволяет программам вычислять декларацию и затем для применения помещать её в вызов proclaim.
Любые упоминаемые имена переменных указывают на значения динамических переменных. Например, выполненная прокламация
указывает на то, что динамическое значение tolerance должно быть всегда числом с плавающей точкой. Подобным образом, любые упоминаемые имена функций указывают на глобальные определения функций.
Прокламации содержат универсальные декларации, которые всегда действуют, кроме случаев сокрытия их локальными декларациями. Например,
рекомендует то, что floor должна быть встроена в места её вызова. Но в ситуации
floor будет вызываться как отдельная функция, так как локальная декларация скрыла прокламацию.
X3J13 voted in January 1989 to clarify that such shadowing does not occur in the case of type declarations. If there is a local type declaration for a special variable and there is also a global proclamation for that same variable, then the value of the variable within the scope of the local declaration must be a member of the intersection of the two declared types. This is consistent with the treatment of nested local type declarations on which X3J13 also voted in January 1989 .
Специальный случай, когда proclaim обрабатывает special, то decl-spec применяется ко всем связываниям и ссылкам на упомянутую переменную. Например, после
в определении функции
параметр x будет связан, как специальная (динамическая) переменная, а не лексическая (статическая). Такой приём должен использоваться аккуратно. Обычный способ определить глобальную специальную переменную это использовать defvar или defparameter.
Этот макрос синтаксически похож на declare и семантически на proclaim. Это выполняемая форма и она может использоваться везде, где может proclaim. Однако, формы decl-spec не вычисляются.
Если вызов этого макроса произошёл на верхнем уровне в файле, обрабатываемом компилятором, то прокламации также будут выполнены во время компиляции. As with other defining macros, it is unspecified whether or not the compile-time side effects of a declaim persist after the file has been compiled (see section 24.1). FIXME