Fixed indentation.
This commit is contained in:
parent
77fed9943d
commit
fec84282fe
@ -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.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user