Finished section on shadowing.
This commit is contained in:
parent
7df5bb41ab
commit
ef2b97c65a
@ -1624,3 +1624,424 @@
|
||||
The function [[http://clhs.lisp.se/Body/f_shadow.htm][=shadow=]] takes a symbol name (or a list of symbol names) and a
|
||||
package name, allocates a symbol with this name if it is not /present/ in
|
||||
this package, and records it in the shadowing list of the package.
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(shadow "SYMB6" "P1")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(package-shadowing-symbols "P1")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(export (intern "SYMB6" "P2") "P2")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(eq 'symb6 'p2:symb6)
|
||||
#+END_SRC
|
||||
|
||||
Once the symbol =p1::symb6= is on the shadowing-list of ="P1"= the existence
|
||||
of a different external symbol with the same name in the used package ="P2"=
|
||||
does not generate a name conflict. The last =eq=-test proves both symbols are
|
||||
really different. Along the same lines, the function [[http://clhs.lisp.se/Body/f_shdw_i.htm][=shadowing-import=]], as
|
||||
clearly indicated in its name, imports a symbol and immediately adds it to
|
||||
the shadowing list, which could resolve a possible name conflict. For example
|
||||
the *different* symbols =p2:symb4= (external in ="P2"=) and =p3::symb4=
|
||||
(internal in ="P3"=) are in our environment; the package ="P1"= uses both
|
||||
packages ="P2"= and ="P3"=, but =p3::symb4= is internal in ="P3"= and
|
||||
therefore not in conflict with =p2::symb4=. Remember also the current default
|
||||
package is ="P1"=. A simple importation of =p3::symb4= in ="P1"= generates a
|
||||
conflict, while a =shadowing-import= adds the imported symbol to the
|
||||
shadowing list, shadowing the symbol =p2:symb4= and resolving the name
|
||||
conflict.
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(multiple-value-list (find-symbol "SYMB4" "P2"))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(multiple-value-list (find-symbol "SYMB4" "P3"))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(multiple-value-list
|
||||
(ignore-errors
|
||||
(import 'p3::symb4 "P1")))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(shadowing-import 'p3::symb4 "P1")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(package-shadowing-symbols "P1")
|
||||
#+END_SRC
|
||||
|
||||
If necessary, =p2:symb4=, shadowed by the internal =symb4= in ="P1"=, remains
|
||||
accessible via the colon notation. The evaluations of the following
|
||||
expressions assign the same symbol value to both symbols as is confirmed by
|
||||
the subsequent '=' form. Evaluating the next =eq= expression proves that
|
||||
both /symbols/ are different. In contrast, because =p1::symb4= was imported
|
||||
from ="P3"=, the last =eq=-test is affirmative.
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(defvar symb4)
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(defvar p2:symb4)
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(setf symb4 (setf p2:symb4 111))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(= symb4 p2:symb4)
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(eq 'symb4 'p2:symb4)
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(eq 'symb4 'p3::symb4)
|
||||
#+END_SRC
|
||||
|
||||
It is even possible to add an /inherited/ symbol to the shadowing list, maybe
|
||||
to declare a precedence with respect to another future competing symbol in
|
||||
another package intended to be used later. This experiment assumes three
|
||||
different packages, where one of them is not yet used. We first "detach" for
|
||||
example the package ="P3"= from ="P1"=, leaving ="P2"= used by ="P1"=.
|
||||
(Remember ="P1"= is the current default package.)
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(unuse-package "P3" "P1")
|
||||
#+END_SRC
|
||||
|
||||
We then install two new external symbols with the same name in ="P2"= and
|
||||
="P3"=:
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(export (intern "SYMB7" "P2") "P2")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(export (intern "SYMB7" "P3") "P3")
|
||||
#+END_SRC
|
||||
|
||||
As we have seen already with essentially the same example, if ="P1"= now
|
||||
decides to use ="P3"=, the two ="SYMB7"= symbols collide:
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(multiple-value-list
|
||||
(ignore-errors
|
||||
(use-package "P3" "P1")))
|
||||
#+END_SRC
|
||||
|
||||
In some context, it could happen that ="P1"= has no reason to use =p3:symb7=
|
||||
directly, and instead would like to give precedence to =p2:symb7=. This can
|
||||
be achieved with a shadowing import.
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(multiple-value-list (find-symbol "SYMB7" "P1") )
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(shadowing-import 'symb7 "P1")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(use-package "P3" "P1")
|
||||
#+END_SRC
|
||||
|
||||
The =shadowing-import= refers to =p2:symb7= implicitly, which is external in
|
||||
a package used by ="P1"= and therefore inherited by ="P1"=. We see how the
|
||||
use of =shadowing-import= solves the name conflict, which otherwise would be
|
||||
raised by =use-package=. Let us review our symbols as seen now from our three
|
||||
packages:
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(multiple-value-list (find-symbol "SYMB7" "P1"))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(multiple-value-list (find-symbol "SYMB7" "P2"))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(eq 'symb7 'p2:symb7)
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(multiple-value-list (find-symbol "SYMB7" "P3"))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp :session pcl :package "P1" :exports both :results value verbatim
|
||||
(package-use-list "P1")
|
||||
#+END_SRC
|
||||
|
||||
The statuses of =symb7= have not changed in ="P2"= and ="P3"=, but seen from
|
||||
="P1"=, the symbol is now /internal/. This is to satisfy the rule that any
|
||||
shadowing symbol in a package must be internal or external in this package,
|
||||
and also a consequence of the implied importation.
|
||||
|
||||
* A mathematical definition of the packaging system.
|
||||
|
||||
We recall that there are three general sets we must study:
|
||||
|
||||
- The set $St$ of /strings/
|
||||
- The set $P$ of /packages/
|
||||
- The set $Sm$ of /symbols/
|
||||
|
||||
There is one important difference: the set $St$ is the /infinite/ set of all
|
||||
the possible strings, while $P$ and $Sm$ are /finite/ sets made of the
|
||||
packages and symbols previously /allocated/ in the current Lisp session.
|
||||
|
||||
We use the notations $pn$ to denote the function =package-name=
|
||||
$pn: P \rightarrow St$ and $sn$ to denote the function =symbol-name=
|
||||
$sn: Sm\rightarrow St$.
|
||||
|
||||
The map $pn$ is /injective/ for the packages; the function
|
||||
$pn: P \rightarrow pn(P)$ defines a 1-1 correspondence between the packages and their respective names. Here, we ignore the potential nicknames of a package, which is not essential for our discussion.
|
||||
|
||||
Every package $P$ contains four /fundamental/ lists:
|
||||
|
||||
- The list $InS(P)$ of its internal symbols
|
||||
- The list $ExS(P)$ of its external symbols
|
||||
- The list $ShgS(P)$ of its shadowing symbols
|
||||
- The list $U(P)$ of its used packages
|
||||
|
||||
More precisely, these lists are lists of /pointers/ to the mentioned objects,
|
||||
or, if you prefer, of the machine addresses of these objects. It is important
|
||||
to understand these lists are made of (pointers to) /symbols/, not of their
|
||||
names. Each of these lists is /without any duplicates/.
|
||||
|
||||
The fundamental lists defined in a package are the source of a relatively
|
||||
extensive terminology, which is detailed now. The set of symbols /present/ in
|
||||
a package $p$, denoted by $PrS(p)$, is defined as the union
|
||||
$PrS(p) := InS(p) \cup ExS(p)$: a symbol is present in a package if it is
|
||||
internal or external in this package. This union is /disjoint/, the
|
||||
intersection $InS(p) \cap ExS(p)$ must be empty. Also the relation
|
||||
$ShgS(P) \subset Pr(P)$ is required. A shadowing symbol of the package $p$
|
||||
must be internal or external in this package, i.e., a shadowing symbol is
|
||||
present.
|
||||
|
||||
Let $q$ be a package used by the package $p$. The symbols of $q$ /shadowed/
|
||||
by a symbol of $p$ are:
|
||||
$$
|
||||
ShdS(q, p) = \{sm \in ExS(q)\;\mathbf{\underline{st}}\;\exists sm' \in ShgS(p)\;\mathbf{\underline{st}}\; sn(sm) = sn(sm')\}
|
||||
$$
|
||||
|
||||
In other words, a /precedence/ relation is defined by the list $ShgS(p)$: if
|
||||
ever a symbol $sm' \in ShgS(p)$ and a symbol $sm\in ExS(q)$ have the same
|
||||
name, then, with respect to the package $p$, $sm'$ takes precedence over
|
||||
$sm$, which means $sm$ is /shadowed/. If $sm'$ is present in $p$ but not
|
||||
shadowing, with $sm'\neq sm$ and $sn(sm') = sn(sm)$, then a name conflict
|
||||
would be raised, which is forbidden.
|
||||
|
||||
The inherited symbols of a package $p$, denoted by $InhS(p)$, are defined as:
|
||||
$$
|
||||
InhS(p) := \Big\{ \bigcup_{q\in U(P)}(ExS(q) − ShdS(q,p)) \Big\} − PrS(P)
|
||||
$$
|
||||
|
||||
A symbol is inherited in a package $p$ if it is external in a /used/ package
|
||||
$q$, not shadowed by a shadowing symbol of $p$, and not present in $p$. The
|
||||
union in the preceding formula is not necessarily disjoint: a symbol can be
|
||||
external in several packages simultaneously, and without causing a name
|
||||
conflict. A symbol could be simultaneously present in $p$ and external in a
|
||||
package $q$ used by $p$. That is why the the last term, $−PrS(P)$, is
|
||||
necessary to define unambiguously what an inherited symbol is.
|
||||
|
||||
Finally the accessible symbols $AccS(p) := PrS(p) \cup InhS(p)$ are the
|
||||
symbols which are present or inherited. The very definition of $InhS(p)$
|
||||
implies that this union is disjoint. In this way, the /status/ of a symbol
|
||||
with respect to a package $p$ via which it is accessible is unambiguously
|
||||
defined as a keyword =:internal=, =:external= or =:inherited=. For a package
|
||||
$q\neq p$ there is no relation whatsoever between the status of some symbol
|
||||
$sm$ with respect to $p$ and its status with respect to $q$.
|
||||
*Exercise:* Show that the sixteen pairs of possible status combinations can
|
||||
be realized!
|
||||
|
||||
It is important to be clear about possible intersections (overlaps) between
|
||||
the lists defined above. Let $p$ be some package and $q$ another package used
|
||||
by $p.$ If $sm\in ExS(q)$ is an external symbol of $q$, the symbol $sm$ /may/
|
||||
also be present in $p$, in which case its status is internal or external, but
|
||||
not inherited. In particular, this does not generate a name conflict, because
|
||||
it is the same symbol which is visible in two different packages via the same
|
||||
name, and a symbol has only /one/ name! Nevertheless its status /with respect
|
||||
to/ $p$ is not inherited. The status of a symbol is so defined
|
||||
deterministically, even if it is present in two interacting packages by one
|
||||
using the other. Of course the same symbol has status external in $q$.
|
||||
|
||||
Following the same logic, if $q,q'\in U(p)$, the intersection
|
||||
$ExS(q)\cap ExS(q')$ is not necessarily empty.
|
||||
|
||||
The Lisp system maintains the /coherence/ of these lists, which is defined as
|
||||
follows:
|
||||
|
||||
*Definition.* A set of packages is /coherent/ if, for every package $p$, the
|
||||
function =symbol-name= defines a 1-1 correspondence
|
||||
$sn: AccS(p) \rightarrow sn(AccS(p))$.
|
||||
|
||||
This map is by definition surjective; it is injective if two different
|
||||
symbols accessible via $p$ have different names. In this way the function
|
||||
=find-symbol= is free of ambiguity. It searches first in the present symbols,
|
||||
and finally in the external symbols of the used packages. It is not necessary
|
||||
to compute the list of shadowed symbols since a shadow/ing/ symbol, which is
|
||||
also a present symbol, is found first. The main purpose of the coherence rule
|
||||
is to prevent users from designing too contorted situations in name scopes,
|
||||
wich are frequently the source of subtle and difficult to find bugs.
|
||||
|
||||
Several symbols with the same name may coexist in an environment. The most
|
||||
common way to access a symbol consists in using its /name/, but /different/
|
||||
symbols may have the /same/ name. In fact, its symbol name is not sufficient
|
||||
to access a symbol, a package must also be specified. This can be the default
|
||||
package, in which case the direct notation without any colons is possible, or
|
||||
the package name can be explicitly used to prefix the symbol name using the
|
||||
one- or two-colon notation. Of course, the symbol so accessed must be defined
|
||||
in a /deterministic/ manner. The definition just given says that a /unique/
|
||||
symbol of some name is accessible from some package.
|
||||
|
||||
The main function in the packaging organization is a map:
|
||||
$$
|
||||
\rho:P \rightarrow [St \rightarrow ((Sm\cup\mathtt{nil})\times Stt)]
|
||||
$$
|
||||
where $Stt$ is a constant set of four symbols, the Lisp symbol =nil=, and
|
||||
three keywords, the possible statuses of an accessible symbol:
|
||||
$$
|
||||
Stt = \{\mathtt{nil}, \mathtt{:internal}, \mathtt{:external}, \mathtt{:inherited}\}
|
||||
$$
|
||||
Because of the assumed coherence of the package configuration, the function
|
||||
$\rho$, an avatar of the function =find-symbol= of a package $p$ and a string
|
||||
$st$, determines a /unique/ symbol named $st$ and accessible via $p$, and
|
||||
also its status. It is possible that the search fails, in which case the
|
||||
function returns the pair =(nil,nil)=. (More precisely =(values nil nil)=.)
|
||||
The second =nil= is a kind of a null status: "There is nothing accessible via
|
||||
$p$ under the name $st$." The relation
|
||||
$\rho(p)(s) = \mathtt{(find-symbol}\;p\;st\mathtt{)}$ is always satisfied.
|
||||
|
||||
It is now relatively simple to understand the various Lisp functions for
|
||||
handling packages and symbols, in particular what name conflicts might be
|
||||
generated.
|
||||
|
||||
** (intern $st\;p$)
|
||||
|
||||
This function first evaluates =(find-symbol= $st\; p$=)=. If a symbol is
|
||||
found, /both/ values of =(find-symbol ...)= are returned.
|
||||
|
||||
If no symbol is found, then Lisp /allocates/ (creates in memory) a new
|
||||
symbol without any value or function value. The =symbol-package= is
|
||||
initialized to $p$ and this symbol is added to $InS(p)$. In this case,
|
||||
=(values= $sm$ =nil)= is returned, the second value =nil= being a code for
|
||||
saying a new symbol has just been allocated.
|
||||
|
||||
No name conflict can be created this way.
|
||||
|
||||
This function is used implicitly by the Lisp reader when it encounters a
|
||||
symbol in an expression. If the colon syntax is not used, the default
|
||||
package is used for $p.$ Otherwise the (capitalized) package name of $p$
|
||||
preceding the colon(s) is read, followed by the (capitalized) =symbol-name=
|
||||
$st$ after the colon(s). Finally, =(intern= $st\; p$=)= is evaluated, which
|
||||
yields the symbol so /read/ by the Lisp reader. In this way, the symbol can
|
||||
be either a pre-existing one or one freshly allocated as a consequence of
|
||||
this reading.
|
||||
|
||||
|
||||
** (unintern $sm\;p$)
|
||||
|
||||
A symbol $sm$ is /interned/ in a package $p$ if it is present in this
|
||||
package. It is /present/ in package $p$ if
|
||||
$sm\in PrS(p) = InS(p) \cup ExS(p).$ Uninterning a symbol asks for this
|
||||
membership to be "revoked."
|
||||
|
||||
If $sm\notin PrS(p)$, nothing is changed and =nil= is returned. Otherwise
|
||||
$sm$ is removed from $InS(p)$ or $ExS(p)$, and also from $Shg(p)$ if $sm$
|
||||
was shadowing with respect to $p$; in this case, =unintern= returns =t=. In
|
||||
the last case, when uninterning a shadowing symbol, a name conflict can be
|
||||
generated: it is possible for symbols $sm'\in ExS(q)$ and $sm''\in ExS(q')$
|
||||
to have the same name while being /different/ symbols in the respective
|
||||
packages $q$ and $q'$ used by $p$, and that this collision was resolved by
|
||||
the symbol $sm$ shadowing both. If this happens, the =unintern= request is
|
||||
rejected.
|
||||
|
||||
Also, if a symbol $sm$ is uninterned from a package $p$ and $p$ is the home
|
||||
package of $sm$, then the home package of $sm$ is modified and becomes
|
||||
=nil=, that is, the symbol becomes homeless. This is the only case where the
|
||||
symbol itself is modified by =unintern=. The same symbol could be external
|
||||
in another package used by $p$, in which case the symbol /remains/
|
||||
accessible via $p$. Otherwise, if the home package was =nil= or another
|
||||
package, it is not modified.
|
||||
|
||||
** (import $sm\; p$)
|
||||
|
||||
This is a request for the symbol $sm$ to be added to $InS(p)$. Lisp first
|
||||
looks for a possible name conflict. This happens only if a /different/
|
||||
symbol $sm'\neq sm$ with the same name ($sn(sm) = sn(sm')$) is already
|
||||
accessible via $p$. If so, the importation is rejected.
|
||||
|
||||
If no name conflict is detected, Lisp proceeds as follows: If the symbol is
|
||||
already /present/, it is left /unchanged/ in $InS(p)$ or $ExS(p)$. Else, if
|
||||
the symbol is /inherited/ because of a package $q$ used by $p$, $ExS(q)$ is
|
||||
left unchanged and $sm$ is added to $InS(p)$ (not $ExS(p)$!). If $sm$ is not
|
||||
accessible via $p$, it is simply added to $InS(p)$.
|
||||
|
||||
In the specific case of an imported homeless symbol, the =symbol-package= of
|
||||
the symbol is updated to $p$. This is the only case where a symbol object is
|
||||
modified by an importation. If the imported symbol is already owned by a
|
||||
package, whatever its home package, it is not modified.
|
||||
|
||||
If the importation succeeds, the symbol will always be /present/ in the
|
||||
target package, even if it was previously accessible only via a used
|
||||
package.
|
||||
|
||||
** (export $sm\; p$)
|
||||
|
||||
The terminology "export" is not really appropriate, "externalize" would be
|
||||
more precise. The user of an =export= expression asks Lisp to record the
|
||||
symbol $sm$ in $ExS(p).$ This is allowed only if $sm$ is accessible from
|
||||
$p.$ In other words, the =export= function cannot /add/ an accessible symbol
|
||||
to $p.$ In view of the rule $InS(p)\cap ExS(p) = \emptyset$, if present in
|
||||
$InS(p)$, the symbol $sm$ is also erased from that list. If $sm$ is external
|
||||
in a package $q$ used by $p$, its status in $q$ remains unchanged, but $sm$
|
||||
is nevertheless added to $ExS(p)$.
|
||||
|
||||
Remember that the =use-package= relation is not transitive. The fact that
|
||||
$sm\in ExS(q)$ makes $sm$ accessible via $p$ using $q$ but not via $p'$
|
||||
using $p$. If it is desired that $sm$ be accessible via $p'$, it is possible
|
||||
to make it external in $p$ by an =export= expression. Another solution would
|
||||
be to import $sm$ in $p'$, an operation which doesn't involve $p$.
|
||||
|
||||
After exporting it, the symbol $sm$ becomes accessible from any package $q$
|
||||
using $p$, that is, if $p\in U(q)$. This can generate a name conflict with
|
||||
a possible /different/ symbol $sm'$ of the same name, which is present in
|
||||
$q$ or accessible via $q$ in another package $p'\in U(p)$, that is, if
|
||||
$sm'\in ExS(p')$. If this happens, the /export/ request is rejected.
|
||||
|
||||
** (unexport $sm\; p$)
|
||||
|
||||
The symbol $sm$ must be accesible via the package $p.$ If the status of
|
||||
$sm$ is /external/, it is downgraded to /internal/. Otherwise it remains
|
||||
unchanged, even if it is /inherited/.
|
||||
|
||||
** (shadow {$sm$ or $st$} $p$)
|
||||
|
||||
It is intended to /import/ the symbol $sm$ in $p$, to record it in the
|
||||
shadowing list $Shg(p)$ of the package $p$, and also to /resolve/ any name
|
||||
conflict possibly raised by the importation.
|
||||
|
||||
This time the first argument must be a /symbol/, a pre-existing one or a
|
||||
symbol just allocated because of its presence in the source statement. The
|
||||
symbol is imported (See the function =import=.) and added to the shadowing
|
||||
list $Shg(p)$ of $p$ if not yet present in this list. This addition to the
|
||||
shadowing list solves the possible name conflicts with symbols inherited
|
||||
from packages used by $p.$ It is possible that a /different/ symbol /sm'/
|
||||
with the same name was /present/ in $p$ beforehand. If so, such a symbol is
|
||||
/uninterned/ from $p$, that is, erased from the lists $InS(p)$, $ExS(p)$ and
|
||||
$Shg(p)$.
|
||||
|
||||
The difference between =shadow= and =shadowing-import= is clarified by the
|
||||
following toy example. We start a new Lisp session, allocate a package
|
||||
="P"= and experiment with symbols named ="A"= and ="B"= in the packages
|
||||
="CL-USER"= and ="P"=.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user