Fixed indentation.

This commit is contained in:
Gerd Heber 2018-01-28 12:01:14 -06:00
parent 77fed9943d
commit fec84282fe

View File

@ -87,13 +87,13 @@
we give a complete mathematical definition of this system as a set of we give a complete mathematical definition of this system as a set of
mathematical formulas. mathematical formulas.
** Main sets of objects. * Main sets of objects.
The first part of the packaging system is made of three disjoint sets: The first part of the packaging system is made of three disjoint sets:
- The set $St$ of *strings*. - The set $St$ of *strings*.
- The set $P$ of *packages*. - The set $P$ of *packages*.
- The set $Sm$ of *symbols*. - The set $Sm$ of *symbols*.
In our description of the packaging system, the statuses of these sets are In our description of the packaging system, the statuses of these sets are
different. Think of the (infinite) set $St$ of /strings/ as made of /all/ different. Think of the (infinite) set $St$ of /strings/ as made of /all/
@ -115,356 +115,474 @@
Lisp session, and they are an essential component of the /current/ Lisp session, and they are an essential component of the /current/
environment. environment.
** Packages * Packages
There is a simple, almost bijective (one-to-one), correspondence between There is a simple, almost bijective (one-to-one), correspondence between
strings and packages, and a convenient place to start our subject. First, at strings and packages, and a convenient place to start our subject. First, at
any time during a Lisp session, a /default package/ is defined and it can be any time during a Lisp session, a /default package/ is defined and it can be
discovered via the global symbol [[http://clhs.lisp.se/Body/v_pkg.htm][=*package*=]]: discovered via the global symbol [[http://clhs.lisp.se/Body/v_pkg.htm][=*package*=]]:
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
*package* *package*
#+END_SRC #+END_SRC
This is to be read as: the /value/ of the /symbol/ =*package*= is the This is to be read as: the /value/ of the /symbol/ =*package*= is the
package whose /name/ is the string ="COMMON-LISP-USER"=. The types =symbol= package whose /name/ is the string ="COMMON-LISP-USER"=. The types =symbol=
and =package= are system-defined, disjoint sets of machine objects. A symbol and =package= are system-defined, disjoint sets of machine objects. A symbol
is frequently used as a convenient intermediate object, which allows the is frequently used as a convenient intermediate object, which allows the
user to reach some object of arbitrary nature, its /value/. Here, user to reach some object of arbitrary nature, its /value/. Here,
=*package*= is a symbol, the value of which is the package named =*package*= is a symbol, the value of which is the package named
="COMMON-LISP-USER"=. Technically, a symbol contains a pointer to its ="COMMON-LISP-USER"=. Technically, a symbol contains a pointer to its
(possible) value, here a package which happens to be the package used (possible) value, here a package which happens to be the package used
ordinarily in a simple Lisp session. There are no facilities to refer to a ordinarily in a simple Lisp session. There are no facilities to refer to a
package object /directly/. However, one can use its /name/ and the function package object /directly/. However, one can use its /name/ and the function
[[http://clhs.lisp.se/Body/f_find_p.htm][=find-package=]] to obtain a reference: [[http://clhs.lisp.se/Body/f_find_p.htm][=find-package=]] to obtain a reference:
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(find-package "COMMON-LISP-USER") (find-package "COMMON-LISP-USER")
#+END_SRC #+END_SRC
Conversely, given a package, the function [[http://clhs.lisp.se/Body/f_pkg_na.htm][=package-name=]] returns its name: Conversely, given a package, the function [[http://clhs.lisp.se/Body/f_pkg_na.htm][=package-name=]] returns its name:
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(package-name (find-package "COMMON-LISP-USER")) (package-name (find-package "COMMON-LISP-USER"))
#+END_SRC #+END_SRC
The example was given to illustrate that the functions =find-package= and The example was given to illustrate that the functions =find-package= and
=package-name= are the inverse of each other, defining a 1-1 correspondence =package-name= are the inverse of each other, defining a 1-1 correspondence
between the packages /currently/ defined in the environment and their between the packages /currently/ defined in the environment and their
respective names, some character strings. Because of rules not of interest respective names, some character strings. Because of rules not of interest
here, it is common and convenient to use only uppercase character strings to here, it is common and convenient to use only uppercase character strings to
name packages. If a name does not correspond to any current package, the name packages. If a name does not correspond to any current package, the
=find-package= function returns the symbol =nil=, usually displayed =find-package= function returns the symbol =nil=, usually displayed
uppercase: uppercase:
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(find-package "COMMON-LISP-user") (find-package "COMMON-LISP-user")
#+END_SRC #+END_SRC
which illustrates that a package name is case-sensitive. Frequently, only a which illustrates that a package name is case-sensitive. Frequently, only a
few packages are in use, and because of their importance, descriptive names few packages are in use, and because of their importance, descriptive names
are used. These descriptive names can be a little long, and it is possible are used. These descriptive names can be a little long, and it is possible
to define and use various /nicknames/ for these names. For example, the to define and use various /nicknames/ for these names. For example, the
="COMMON-LISP-USER"= package usually has the nicknames ="CL-USER"= and ="COMMON-LISP-USER"= package usually has the nicknames ="CL-USER"= and
="USER"=. The function [[http://clhs.lisp.se/Body/f_pkg_ni.htm][=package-nicknames=]] can be used to retrieve the list ="USER"=. The function [[http://clhs.lisp.se/Body/f_pkg_ni.htm][=package-nicknames=]] can be used to retrieve the list
of nicknames (strings) for a package, which doesn't include the name of the of nicknames (strings) for a package, which doesn't include the name of the
package. package.
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(find-package "COMMON-LISP-USER") (find-package "COMMON-LISP-USER")
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(package-nicknames (find-package "COMMON-LISP-USER")) (package-nicknames (find-package "COMMON-LISP-USER"))
#+END_SRC #+END_SRC
If a package is to be unambiguously identified by its name or one of its If a package is to be unambiguously identified by its name or one of its
nicknames, two different packages must have disjoint sets of nicknames, two different packages must have disjoint sets of
/name + nicknames/. /name + nicknames/.
** Tracking a symbol. * Tracking a symbol.
The Lisp symbols are very particular when compared to the identifiers of The Lisp symbols are very particular when compared to the identifiers of
other programming languages. They persist throughout the runtime of an other programming languages. They persist throughout the runtime of an
environment and are an important component of the power of Lisp. A package environment and are an important component of the power of Lisp. A package
is referenced via its name; the same goes for a symbol, but the process is is referenced via its name; the same goes for a symbol, but the process is
much more complex. The first and most common method to create or "to much more complex. The first and most common method to create or "to
/allocate/ a symbol" consists in just writing it down and passing it to the /allocate/ a symbol" consists in just writing it down and passing it to the
Lisp reader using the standard Lisp conventions. In a Lisp environment, Lisp reader using the standard Lisp conventions. In a Lisp environment,
there is a set of "pre-defined" symbols ready to be used. To caution the there is a set of "pre-defined" symbols ready to be used. To caution the
reader about the complexity of the subject, we begin with a seemingly reader about the complexity of the subject, we begin with a seemingly
strange example: strange example:
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (find-symbol "X" "COMMON-LISP-USER")) (multiple-value-list (find-symbol "X" "COMMON-LISP-USER"))
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (ignore-errors x)) (multiple-value-list (ignore-errors x))
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (find-symbol "X" "COMMON-LISP-USER")) (multiple-value-list (find-symbol "X" "COMMON-LISP-USER"))
#+END_SRC #+END_SRC
The function [[http://clhs.lisp.se/Body/f_find_s.htm][=find-symbol=]] is analogous to the function =find-package=: The function [[http://clhs.lisp.se/Body/f_find_s.htm][=find-symbol=]] is analogous to the function =find-package=:
given some /name/, a character string, it looks for a symbol with this name. given some /name/, a character string, it looks for a symbol with this name.
Remember the correspondence between packages and names? A similar Remember the correspondence between packages and names? A similar
correspondence exists between symbols and names, but it's more involved. In correspondence exists between symbols and names, but it's more involved. In
particular, a name is /never sufficient/ to determine a symbol, a particular, a name is /never sufficient/ to determine a symbol, a
/package/ is also necessary. This is why the =find-symbol= function requires /package/ is also necessary. This is why the =find-symbol= function requires
/two/ arguments, the name of the symbol and the package with respect to /two/ arguments, the name of the symbol and the package with respect to
which the search is to be done. which the search is to be done.
At the beginning of our story, no symbol with the name ="X"= existed in the At the beginning of our story, no symbol with the name ="X"= existed in the
default package ="COMMON-LISP-USER"=, and the return value of =find-symbol= default package ="COMMON-LISP-USER"=, and the return value of =find-symbol=
is negative, =nil=. (We will explain the second =nil= value in a moment.) is negative, =nil=. (We will explain the second =nil= value in a moment.)
Then we pass the Lisp reader the one character expression '=x='. Lisp Then we pass the Lisp reader the one character expression '=x='. Lisp
evaluates it according to its /read-eval-print/ cycle. First, Lisp evaluates it according to its /read-eval-print/ cycle. First, Lisp
/reads/ the expression and notices that the symbol =x= is used. It examines /reads/ the expression and notices that the symbol =x= is used. It examines
the current package ="COMMON-LISP-USER"=, and does /not/ find such a symbol. the current package ="COMMON-LISP-USER"=, and does /not/ find such a symbol.
Before doing anything else, Lisp /allocates/ (creates) this symbol, the Before doing anything else, Lisp /allocates/ (creates) this symbol, the
right terminology being: "Lisp /interns/ a symbol =x= of name ="X"= in the right terminology being: "Lisp /interns/ a symbol =x= of name ="X"= in the
package ="COMMON-LISP-USER"=." To refer to this symbol, the pair made of package ="COMMON-LISP-USER"=." To refer to this symbol, the pair made of
/its/ name ="X"= and the (not /its/!!) package ="COMMON-LISP-USER"= are /its/ name ="X"= and the (not /its/!!) package ="COMMON-LISP-USER"= are
necessary, but it would be cumbersome to have to write the expression necessary, but it would be cumbersome to have to write the expression
=(find-symbol "X" "COMMON-LISP-USER")= every time this symbol is used. To =(find-symbol "X" "COMMON-LISP-USER")= every time this symbol is used. To
simplify the process of referring to a symbol the designers of Lisp have simplify the process of referring to a symbol the designers of Lisp have
organized the workspace as follows: if a symbol is read, its character organized the workspace as follows: if a symbol is read, its character
string is capitalized, giving its /name/, and the default package is string is capitalized, giving its /name/, and the default package is
assumed. In other words, the text ='x'= is roughly equivalent to the text assumed. In other words, the text ='x'= is roughly equivalent to the text
=(find-symbol "X" "COMMON-LISP-USER")=. How convenient! ('Roughly', because =(find-symbol "X" "COMMON-LISP-USER")=. How convenient! ('Roughly', because
'=x=' may trigger the allocation of a symbol. In contrast, =find-symbol= '=x=' may trigger the allocation of a symbol. In contrast, =find-symbol=
never allocates a symbol; but see the function =intern= later.) In the never allocates a symbol; but see the function =intern= later.) In the
second expression of our example, once Lisp has "understood" that the user second expression of our example, once Lisp has "understood" that the user
intends to use the symbol =x=, and observing that such a symbol is not intends to use the symbol =x=, and observing that such a symbol is not
present in the package ="COMMON-LISP-USER"=, it allocates a symbol of name present in the package ="COMMON-LISP-USER"=, it allocates a symbol of name
="X"= and /interns/ it in the package ="COMMON-LISP-USER"=. More ="X"= and /interns/ it in the package ="COMMON-LISP-USER"=. More
specifically, a pointer referring to the just allocated symbol is added to specifically, a pointer referring to the just allocated symbol is added to
the list $InS(p)$ of the internal symbols of the package $p$. the list $InS(p)$ of the internal symbols of the package $p$.
Note also that it is common in Lisp to input the symbols in lowercase Note also that it is common in Lisp to input the symbols in lowercase
letters, and Lisp prints them in uppercase. This might be convenient for letters, and Lisp prints them in uppercase. This might be convenient for
distinguishing input from output in an interactive session, but requires distinguishing input from output in an interactive session, but requires
some clarification. In particular, there is no difference between the some clarification. In particular, there is no difference between the
symbols =nil= and =NIL=, whereas the strings ="nil"= and ="NIL"= are symbols =nil= and =NIL=, whereas the strings ="nil"= and ="NIL"= are
different. different.
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (find-symbol "nil" "COMMON-LISP-USER")) (multiple-value-list (find-symbol "nil" "COMMON-LISP-USER"))
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (find-symbol "NIL" "COMMON-LISP-USER")) (multiple-value-list (find-symbol "NIL" "COMMON-LISP-USER"))
#+END_SRC #+END_SRC
The fruitless search for a /symbol/ with the lower-case name ="nil"= (a The fruitless search for a /symbol/ with the lower-case name ="nil"= (a
/string/) returns a double negative answer, but it is the second =NIL= that /string/) returns a double negative answer, but it is the second =NIL= that
is meaningful! Compare that with the second expression which has the same is meaningful! Compare that with the second expression which has the same
first return value, but a different second one. The symbol =NIL= also plays first return value, but a different second one. The symbol =NIL= also plays
in Lisp the role of the boolean /false/, which creates an ambiguity: if the in Lisp the role of the boolean /false/, which creates an ambiguity: if the
answer is the symbol =NIL= is that a negative answer or is it a positive answer is the symbol =NIL= is that a negative answer or is it a positive
answer made of the symbol =NIL=? The ambiguity is resolved by the /second/ answer made of the symbol =NIL=? The ambiguity is resolved by the /second/
return value. In the first case, the second =NIL= /confirms/ that the first return value. In the first case, the second =NIL= /confirms/ that the first
=NIL= is to be interpreted as the boolean /false/. In the second expression, =NIL= is to be interpreted as the boolean /false/. In the second expression,
the second return value =:INHERITED=, not a negative, indicates that the the second return value =:INHERITED=, not a negative, indicates that the
symbol =NIL= has been found, and that its /accessibility/ via the package symbol =NIL= has been found, and that its /accessibility/ via the package
="COMMON-LISP-USER"= is /inherited/, a point to be explained later. In other ="COMMON-LISP-USER"= is /inherited/, a point to be explained later. In other
words, the function =find-symbol= returns a genuine symbol /and/ its words, the function =find-symbol= returns a genuine symbol /and/ its
accessibility via the package argument, or a pair of =nil='s if no symbol is accessibility via the package argument, or a pair of =nil='s if no symbol is
found. The logician can deduce that an accessibility cannot be the symbol found. The logician can deduce that an accessibility cannot be the symbol
=nil=! =nil=!
Let us return to the one character expression '=x='. The read part of the Let us return to the one character expression '=x='. The read part of the
read-eval-print loop cycle reads the symbol =x= and interns it in the read-eval-print loop cycle reads the symbol =x= and interns it in the
package ="COMMON-LISP-USER"=. The expression is /read/ and must now be package ="COMMON-LISP-USER"=. The expression is /read/ and must now be
/evaluated/. The evaluation of a symbol consists in looking for a /value/ /evaluated/. The evaluation of a symbol consists in looking for a /value/
of this symbol. To this end a value pointer in the symbol's internal of this symbol. To this end a value pointer in the symbol's internal
representation is examined. In this case it is found that, at this time, representation is examined. In this case it is found that, at this time,
there is no value for the freshly allocated symbol =x=. Therefore the /eval/ there is no value for the freshly allocated symbol =x=. Therefore the /eval/
step of the /read-eval-print/ cycle generates an error, terminating the step of the /read-eval-print/ cycle generates an error, terminating the
cycle with an informative error message. In any case, a symbol of name cycle with an informative error message. In any case, a symbol of name
="X"= is now present in the package ="COMMON-LISP-USER"=, as confirmed by ="X"= is now present in the package ="COMMON-LISP-USER"=, as confirmed by
the value of the last expression. The symbol's accessibility via the the value of the last expression. The symbol's accessibility via the
="COMMON-LISP-USER"= package is /internal/, which is to be explained later. ="COMMON-LISP-USER"= package is /internal/, which is to be explained later.
** Examining a symbol. * Examining a symbol.
A symbol is a Lisp object with a rich internal structure and there are A symbol is a Lisp object with a rich internal structure and there are
several functions for exploring symbols and their properties. Let us several functions for exploring symbols and their properties. Let us
examine in detail the symbol =x= allocated in the previous section. examine in detail the symbol =x= allocated in the previous section.
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(symbol-name 'x) (symbol-name 'x)
#+END_SRC #+END_SRC
The [[http://clhs.lisp.se/Body/f_symb_2.htm][=symbol-name=]] function returns the /name/ of a symbol; it is analogous The [[http://clhs.lisp.se/Body/f_symb_2.htm][=symbol-name=]] function returns the /name/ of a symbol; it is analogous
to the =package-name= function for a package. The Lisp function to the =package-name= function for a package. The Lisp function
=symbol-name= is crucial for our subject, and we denote it as a mathematical =symbol-name= is crucial for our subject, and we denote it as a mathematical
function $sn: Sm \longrightarrow St$, a function which in general is not function $sn: Sm \longrightarrow St$, a function which in general is not
injective: several symbols may have the same name, this is our main subject. injective: several symbols may have the same name, this is our main subject.
Note that in the previous expression the symbol =x= has been quoted ='x= to Note that in the previous expression the symbol =x= has been quoted ='x= to
prevent its evaluation. More precisely, ='x= is an abbreviation for the prevent its evaluation. More precisely, ='x= is an abbreviation for the
expression =(quote x)=, where [[http://clhs.lisp.se/Body/s_quote.htm][=quote=]] is a /special/ function which /does expression =(quote x)=, where [[http://clhs.lisp.se/Body/s_quote.htm][=quote=]] is a /special/ function which /does
not/ evaluate its argument, and it returns this argument as is. Hence, the not/ evaluate its argument, and it returns this argument as is. Hence, the
previous expression is equivalent to: previous expression is equivalent to:
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(symbol-name (quote x)) (symbol-name (quote x))
#+END_SRC #+END_SRC
Here, the non-quoted =x= does not generate an error. If instead you do not Here, the non-quoted =x= does not generate an error. If instead you do not
quote the symbol =x= (implicitly via ='=, or explicitly via =quote=) it will quote the symbol =x= (implicitly via ='=, or explicitly via =quote=) it will
be evaluated before being used and generate an error: be evaluated before being used and generate an error:
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (ignore-errors (symbol-name x))) (multiple-value-list
#+END_SRC (ignore-errors
(symbol-name x)))
#+END_SRC
The package which /owns/ a symbol, its /home package/, can be determined The package which /owns/ a symbol, its /home package/, can be determined
with the function [[http://clhs.lisp.se/Body/f_symb_3.htm][=symbol-package=]]. with the function [[http://clhs.lisp.se/Body/f_symb_3.htm][=symbol-package=]].
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(symbol-package 'x) (symbol-package 'x)
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (find-symbol "X" "COMMON-LISP-USER")) (multiple-value-list (find-symbol "X" "COMMON-LISP-USER"))
#+END_SRC #+END_SRC
As we have just seen, a symbol produces a name and a package (with the help As we have just seen, a symbol produces a name and a package (with the help
of =symbol-name= and =symbol-package=). Conversely, given a name and a of =symbol-name= and =symbol-package=). Conversely, given a name and a
package, =find-symbol= produces the symbol with this name /via/ this package, =find-symbol= produces the symbol with this name /via/ this
package. The reader might think that there is a correspondence between package. The reader might think that there is a correspondence between
symbols and pairs of strings and packages: symbols and pairs of strings and packages:
$$Sm \longleftrightarrow St\times P$$ $$Sm \longleftrightarrow St\times P$$
However, the situation is more involved: for the beginner, this might be a However, the situation is more involved: for the beginner, this might be a
convenient point of view, but in fact such a point of view is wrong. If you convenient point of view, but in fact such a point of view is wrong. If you
intend to fully understand the complex relationship between strings, intend to fully understand the complex relationship between strings,
packages and symbols, please forget this tempting but terribly misleading packages and symbols, please forget this tempting but terribly misleading
correspondence. The goal of the next sections is to establish the correct correspondence. The goal of the next sections is to establish the correct
point of view. For completeness we finish this section with a brief glance point of view. For completeness we finish this section with a brief glance
at the other data possibly stored in a symbol. A symbol can have a value. at the other data possibly stored in a symbol. A symbol can have a value.
You may remember that in our Lisp session the symbol =x= does not (yet) have You may remember that in our Lisp session the symbol =x= does not (yet) have
a value. This can be established by the predicate [[http://clhs.lisp.se/Body/f_boundp.htm][=boundp=]]: a value. This can be established by the predicate [[http://clhs.lisp.se/Body/f_boundp.htm][=boundp=]]:
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(boundp 'x) (boundp 'x)
#+END_SRC #+END_SRC
The main method to give a symbol a value is the [[http://clhs.lisp.se/Body/m_setf_.htm][=setf=]] function (a macro). The main method to give a symbol a value is the [[http://clhs.lisp.se/Body/m_setf_.htm][=setf=]] function (a macro).
In most Common Lisp implementations, the =setf= macro may be used directly, In most Common Lisp implementations, the =setf= macro may be used directly,
in which case the default status of the argument symbol is /variable/. In in which case the default status of the argument symbol is /variable/. In
strict ANSI implementations such as SBCL here, a =defvar= statement is strict ANSI implementations such as SBCL here, a =defvar= statement is
required to explicitly define this status. Other possible statuses are required to explicitly define this status. Other possible statuses are
/constant/ (via =defconstant=) and /parameter/ (via =defparameter=). /constant/ (via =defconstant=) and /parameter/ (via =defparameter=).
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(defvar x) (defvar x)
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(setf x '(4 5 6)) (setf x '(4 5 6))
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(boundp 'x) (boundp 'x)
#+END_SRC #+END_SRC
Note that the first argument of =setf=, the symbol =x=, is not evaluated. Note that the first argument of =setf=, the symbol =x=, is not evaluated.
Otherwise an error would be generated, since the symbol =x= does not yet Otherwise an error would be generated, since the symbol =x= does not yet
have a value. After the =(setf ...)= expression has been evaluated, the have a value. After the =(setf ...)= expression has been evaluated, the
symbol =x= does have a value, in this case, the list =(4 5 6)=. This value symbol =x= does have a value, in this case, the list =(4 5 6)=. This value
would now be the result of the evaluation of the expression =x=. It can also would now be the result of the evaluation of the expression =x=. It can also
be obtained with the function [[http://clhs.lisp.se/Body/f_symb_5.htm][=symbol-value=]]. (In this tutorial, we do not be obtained with the function [[http://clhs.lisp.se/Body/f_symb_5.htm][=symbol-value=]]. (In this tutorial, we do not
study the possible difference between, on the one hand, the simple study the possible difference between, on the one hand, the simple
/evaluation/ of the symbol =x= asked for by the expression ='x'= and the /evaluation/ of the symbol =x= asked for by the expression ='x'= and the
/evaluation/ of =(symbol-value 'x)= on the other. In our elementary examples /evaluation/ of =(symbol-value 'x)= on the other. In our elementary examples
there is no difference between the two. Possible differences might come from there is no difference between the two. Possible differences might come from
different variable scopes, such as /lexical/ or /dynamic/, but this subject different variable scopes, such as /lexical/ or /dynamic/, but this subject
is not studied here.) is not studied here.)
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
x x
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(symbol-value 'x) (symbol-value 'x)
#+END_SRC #+END_SRC
Don't forget to quote the symbol! See the following error: Don't forget to quote the symbol! See the following error:
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (ignore-errors (symbol-value x))) (multiple-value-list
#+END_SRC (ignore-errors
(symbol-value x)))
#+END_SRC
A symbol can also have a /functional value/. This does not mean that the A symbol can also have a /functional value/. This does not mean that the
value we just discussed could be a function (which it could be!). It means value we just discussed could be a function (which it could be!). It means
that /besides/ the previous value, a symbol can also have an /additional/ that /besides/ the previous value, a symbol can also have an /additional/
value, a function, which can be used independently of the "ordinary" value value, a function, which can be used independently of the "ordinary" value
of this symbol. For example the function $n \mapsto 10−n$ could be recorded of this symbol. For example the function $n \mapsto 10 - n$ could be recorded
as the /functional/ value of the same symbol, and this function could then as the /functional/ value of the same symbol, and this function could then
be used as shown below. be used as shown below.
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(defun x (n) (- 10 n)) (defun x (n) (- 10 n))
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(x 3) (x 3)
#+END_SRC #+END_SRC
Both values coexist in the symbol without any interference: Both values coexist in the symbol without any interference:
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(symbol-value 'x) (symbol-value 'x)
#+END_SRC #+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim #+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(symbol-function 'x) (symbol-function 'x)
#+END_SRC #+END_SRC
and can be used jointly and independently: and can be used jointly and independently:
#+BEGIN_SRC lisp :session pcl :exports both #+BEGIN_SRC lisp :session pcl :exports both
(x (first x)) (x (first x))
#+END_SRC #+END_SRC
You might already suspect that the position of =x= just after a left You might already suspect that the position of =x= just after a left
parenthesis =(x ...)= makes Lisp extract the /functional/ value and not the parenthesis =(x ...)= makes Lisp extract the /functional/ value and not the
"ordinary" value. This is correct, but not the subject of this tutorial. "ordinary" value. This is correct, but not the subject of this tutorial.
Finally, we mention only in passing the following: Finally, we mention only in passing the following:
1. A symbol can have a functional value while not having an ordinary value. 1. A symbol can have a functional value while not having an ordinary value.
2. An ordinary value can be a functional object, usually then called via 2. An ordinary value can be a functional object, usually then called via
=funcall= or =apply=. =funcall= or =apply=.
3. A symbol also contains a property list or =plist=, with many possible 3. A symbol also contains a property list or =plist=, with many possible
uses, but not at all studied here. uses, but not at all studied here.
The internal structure of the [[http://clhs.lisp.se/Body/t_symbol.htm#symbol][symbol]] =x= might be visualized thus: The internal structure of the [[http://clhs.lisp.se/Body/t_symbol.htm#symbol][symbol]] =x= might be visualized thus:
#+BEGIN_EXAMPLE #+BEGIN_EXAMPLE
+-----------------+ +-----------------+
| Name o-|-----> "x" | Name o-|-----> "x"
+-----------------+ +-----------------+
| Value o-|-----> (4 5 6) | Value o-|-----> (4 5 6)
+-----------------+ +-----------------+
| Function o-|-----> (lambda (n) (- 10 n)) | Function o-|-----> (lambda (n) (- 10 n))
+-----------------+ +-----------------+
| Package o-|-----> #<PACKAGE "COMMON-LISP-USER"> | Package o-|-----> #<PACKAGE "COMMON-LISP-USER">
+ ----------------+ + ----------------+
| Property list o-|-----> NIL | Property list o-|-----> NIL
+-----------------+ +-----------------+
#+END_EXAMPLE #+END_EXAMPLE
** But what the hell is a package? * But what the hell is a package?
Now we attack the heart of our subject.\\ Now we attack the heart of our subject.\\
**Fact 1:** A package $p\in P$ maintains four fundamental lists: **Fact 1:** A package $p\in P$ maintains four fundamental lists:
- A list $InS(p)$ of its internal symbols. - A list $InS(p)$ of its internal symbols.
- A list $ExS(p)$ of its external symbols. - A list $ExS(p)$ of its external symbols.
- A list $ShgS(p)$ of its shadowing symbols. - A list $ShgS(p)$ of its shadowing symbols.
- A list $U(p)$ of its used packages. - A list $U(p)$ of its used packages.\\
The first important fact toward understanding the subject is this: the first
three lists are lists of /symbols/ or, more precisely, lists of pointers
(machine addresses) aimed at the symbols. Every symbol has a /unique/
"existence": a symbol is a unique machine object in the environment, but
/several/ packages may /see/ the same symbol, that is, include the machine
address of this symbol. In particular these lists are not lists of symbol
names (strings). There is another mechanism that allows Lisp to reach a
symbol given its name. Every symbol can be accessed directly via a suitable
package, and several packages can in general play this role for the same
symbol at a given moment in a Lisp session. For example, all the
[[http://clhs.lisp.se/Front/X_Symbol.htm][standard Lisp symbols]] in the ="COMMON-LISP"= package typically are
accessible via any package.
No duplicate symbol (more precisely, no duplicate pointer) is to be found in
each of these lists. Also the relations $InS(p)\cap ExS(p)=\emptyset$ and
$ShgS(p)\subset InS(p)\cup ExS(p)$ must be satisfied, for reasons to be
studied later.\\
**Fact 2:** Given the current set of packages, assumed /coherent/, and given
the current state of all the fundamental lists of these packages, the
function =find-symbol= can unambiguously determine /whether/ a symbol of a
given name (some string) is /accessible/ via some package; if so, this
symbol is unique.\\
The importance of the package argument of =find-symbol= could make the
reader believe the function =symbol-package= will be useful for various
tests. This is not the case: All this function returns is the "birth place"
of the symbol, technically called its /home package/, which says almost
nothing about the current status of this symbol with respect to any package.
All it says is that at least it is /interned/ in this package. In
particular, a symbol can be accessible via several packages, possibly
different from its home package. Here is a simple illustration:
#+BEGIN_SRC lisp :session pcl :exports both
(symbol-package 'nil)
#+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (find-symbol "NIL" "COMMON-LISP"))
#+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(multiple-value-list (find-symbol "NIL" "COMMON-LISP-USER"))
#+END_SRC
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(eq (find-symbol "NIL" "COMMON-LISP")
(find-symbol "NIL" "COMMON-LISP-USER"))
#+END_SRC
The /home package/ of =nil= is ="COMMON-LISP"=, and this symbol of name
="NIL"= is accessible via ="COMMON-LISP"=, but also via
="COMMON-LISP-USER"=, though not with the same status. It is /external/ in
the first case and /inherited/ in the second case, points to be examined
later. The value (=T=) of the last expression /proves/ that both symbols,
determined by =find-symbol= via different packages, in fact are the same.
Fact 2 can be made a little more precise: At any given time during a Lisp
session, a set $P$ of packages and a set $Sm$ of symbols are defined. The
various lists of symbols $InS(p)$, $ExS(p)$ and $ShgS(p)$, and the list
$U(p)$ of packages used by a package $p\in P$ together define without any
ambiguity which symbols are accessible via the package $p$. In other words,
there is a well defined function $\rho$:
$$
\rho: P \longrightarrow [St \longrightarrow Sm \cup \{\mathtt{nil}\}]
$$
We chose the letter $\rho$ for reader, because this function is mainly used
by the reader. Our "mathematical" function $\rho$ is nothing but an avatar
of the Lisp function =find-symbol=. Let $p\in P$ be a package and
$st\in St$ be a string. Then:
$$
\rho(p)(st) = (\mathtt{find-symbol}\; st\; p)
$$
The left-hand side uses the standard mathematical functional notation, and
the right-hand one uses the Lisp notation. If no symbol is found for a pair
$(st, p)$, the symbol (!) =nil= is returned and the second value of
=find-symbol=, the symbol =nil= again, tells the user that the symbol search
did not return anything. A package $p$ is nothing but a way of defining the
function $\rho(p):St\longrightarrow Sm\cup\{\mathtt{nil}\}$. In other words,
the four fundamental lists of a package determine what character strings
appear as the names of the symbols accessible via this package.
This approach is described in detail now.
* Internal symbols.
The first fundamental list of a package is the list of its /internal
symbols/. It is a pity that no standard Lisp function can produce this list,
but here is a simple solution to the problem:
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(defun package-internal-symbols (package)
(let ((rslt))
(do-symbols (s package)
(when (eq (second
(multiple-value-list
(find-symbol (symbol-name s) package)))
:internal)
(push s rslt)))
rslt))
#+END_SRC
We can list now all the internal symbols of a package:
#+BEGIN_SRC lisp :session pcl :exports both :results value verbatim
(package-internal-symbols "COMMON-LISP-USER")
#+END_SRC
In fact, only the first ten internal symbols are displayed. We see in
particular the symbols =package-internal-symbols=, =s= and =rslt= used in
the definition of our function. Some are rather esoteric, strictly speaking
illegal: at the beginning of a Lisp session, the ="COMMON-LISP-USER"=
package should in principle be void of symbols. To make our experiments more
understandable it is better to allocate and use toy packages. The
[[http://clhs.lisp.se/Body/m_defpkg.htm][=defpackage=]] function (a macro) allocates a package of a given name.