[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

[Newbie] Confusing about symbols and packages about common lisp

zhz shi

4/9/2015 5:57:00 AM

Hi all,

I'm a newbie to common lisp and I know symbol is the key idea behind the whole language(and all LISP), but sometimes I found myself are really confused about it.

Like this loop code snippet: (loop for i from 1 to 10 collect i), which will cause 5 symbols created and interned into current package(FOR, I, FROM, TO, COLLECT). (loop :for i :from 1 :to 10 :collect i) will intern related keywords in KEYWORD package. Could anybody kindly explain to me why CL is implemented this way? Is this a sort of pollution to packages(current package or keyword package) ?

Another is about the KEYWORD package, why is there a need of package KERWORD in cl? From HyperSpec it says "This makes it notationally convenient to use keywords when communicating between programs in different packages.", so what is the essential meaning of "communicating between programs in different packages"?

Any help/explaination/links is appreciated :-)

BR, zhz
15 Answers

Barry Margolin

4/9/2015 7:00:00 AM

0

In article <2b90ba4a-7399-43c3-98f0-ad37dfbf7d04@googlegroups.com>,
zhz shi <messi.shizz@gmail.com> wrote:

> Hi all,
>
> I'm a newbie to common lisp and I know symbol is the key idea behind the
> whole language(and all LISP), but sometimes I found myself are really
> confused about it.
>
> Like this loop code snippet: (loop for i from 1 to 10 collect i), which will
> cause 5 symbols created and interned into current package(FOR, I, FROM, TO,
> COLLECT). (loop :for i :from 1 :to 10 :collect i) will intern related
> keywords in KEYWORD package. Could anybody kindly explain to me why CL is
> implemented this way? Is this a sort of pollution to packages(current package
> or keyword package) ?

Symbols that are typed have to be interned in some package, so that when
you reuse a symbol it will be recognized as the same symbol each time.
Unless you use a package prefix, they get interned in the current
package.

>
> Another is about the KEYWORD package, why is there a need of package KERWORD
> in cl? From HyperSpec it says "This makes it notationally convenient to use
> keywords when communicating between programs in different packages.", so what
> is the essential meaning of "communicating between programs in different
> packages"?

The most common case is when you're calling functions that have keyword
arguments.

(delete something somelist :key #'car)

Using the keyword :key makes it easy to pass this option argument
between the caller's package and the package that the DELETE function
was written in. Otherwise, these symbols would have to be exported from
the internal package and imported into every caller's package.

Note that the LOOP macro is a special case. It was inherited from old
dialects of Lisp that didn't have packages, everything was in one, big
namespace. So it doesn't use symbol equality to match all its special
words, it just compares them by name. So they can be in any package and
they'll still work.

But all other functions and macros that want to be callable easily from
any other package use keywords.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Pascal J. Bourguignon

4/9/2015 7:41:00 AM

0


Oh, and I wanted also to mention another consideration:

Not all symbols used in sources are kept along when you compile it, far
from it.

Only the quoted symbols and the globally bound are forwarded from the
compilation environment to the run-time environment.

Therefore when you compile a file such as:

(defpackage "EX3"
(:use "CL")
(:export "P"))
(in-package "EX3")
(defun p (x)
(loop for i below x sum (* i i)))

and later load the compiled file (in a different image):

cl-user> (load "/tmp/ex3.lx64fsl")
#P"/tmp/ex3.lx64fsl"

Only the exported symbols and a few other symbols useful for debugging
and backtraces remain:

cl-user> (do-symbols (s (find-package "EX3"))
(unless (eql (symbol-package s) (load-time-value (find-package "CL")))
(print s)))

ex3:p
ex3::i
ex3::x
nil

You could even expect that when compiled with (optimize (debug 0)), some
implementation would throw away I and X too.

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Marco Antoniotti

4/9/2015 7:42:00 AM

0

On Thursday, April 9, 2015 at 7:57:30 AM UTC+2, zhz shi wrote:
> Hi all,
>
> I'm a newbie to common lisp and I know symbol is the key idea behind the whole language(and all LISP), but sometimes I found myself are really confused about it.
>
> Like this loop code snippet: (loop for i from 1 to 10 collect i), which will cause 5 symbols created and interned into current package(FOR, I, FROM, TO, COLLECT). (loop :for i :from 1 :to 10 :collect i) will intern related keywords in KEYWORD package. Could anybody kindly explain to me why CL is implemented this way? Is this a sort of pollution to packages(current package or keyword package) ?

"Pollution" is not a problem most of the times. 90% of anything is made of dirt :) So, yes, things are not that clean but... It usually turns out that the KEYWORD package already includes the LOOP keywords and I wouldn't be surprised if - under the hood - they were also exported by the CL package, which is used by most packages.

> Another is about the KEYWORD package, why is there a need of package KERWORD in cl? From HyperSpec it says "This makes it notationally convenient to use keywords when communicating between programs in different packages.", so what is the essential meaning of "communicating between programs in different packages"?
>
> Any help/explaination/links is appreciated :-)

Well, that CL is a historically accumulation of features is well known. We all live with it. Personally I can see the idiosyncrasy of LOOP and KEYWORDs and their less than aesthetically pleasing qualities. However, there are much much uglier warts in the language and we all love picking at them :) But the warts of the language are pretty much like those on the chin of a witch out of a Terry Pratchett's novel. Myself, I can't think of more resourceful characters. :)

Cheers
--
MA

Pascal J. Bourguignon

4/9/2015 7:45:00 AM

0

Marco Antoniotti <marcoxa@gmail.com> writes:

> "Pollution" is not a problem most of the times. 90% of anything is
> made of dirt :) So, yes, things are not that clean but... It usually
> turns out that the KEYWORD package already includes the LOOP keywords
> and I wouldn't be surprised if - under the hood - they were also
> exported by the CL package, which is used by most packages.

They couldn't, it's forbidden by the standard to export from CL any
other symbols than those that are specified. LOOP keywords, apart from
(= APPEND DO IF NCONC RETURN SYMBOL THE UNLESS WHEN), are not specified
to be exported.

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

zhz shi

4/9/2015 2:50:00 PM

0

On Thursday, April 9, 2015 at 3:49:36 PM UTC+8, informatimago wrote:
> Oh, and I wanted also to mention another consideration:
>
> Not all symbols used in sources are kept along when you compile it, far
> from it.
>
> Only the quoted symbols and the globally bound are forwarded from the
> compilation environment to the run-time environment.
>
> Therefore when you compile a file such as:
>
> (defpackage "EX3"
> (:use "CL")
> (:export "P"))
> (in-package "EX3")
> (defun p (x)
> (loop for i below x sum (* i i)))
>
> and later load the compiled file (in a different image):
>
> cl-user> (load "/tmp/ex3.lx64fsl")
> #P"/tmp/ex3.lx64fsl"
>
> Only the exported symbols and a few other symbols useful for debugging
> and backtraces remain:
>
> cl-user> (do-symbols (s (find-package "EX3"))
> (unless (eql (symbol-package s) (load-time-value (find-package "CL")))
> (print s)))
>
> ex3:p
> ex3::i
> ex3::x
> nil
>
> You could even expect that when compiled with (optimize (debug 0)), some
> implementation would throw away I and X too.
>
> --
> __Pascal Bourguignon__ http://www.informat...
> "The factory of the future will have only two employees, a man and a
> dog. The man will be there to feed the dog. The dog will be there to
> keep the man from touching the equipment." -- Carl Bass CEO Autodesk

Thanks for your explanation all answers from other guys, it's very useful info for me :-) :-)

However, I still don't know why we must pass the same symbol to the function when using &key arguments. :(

My guess is, when we define a function with &key argument:

(in-package :cl-user)
(defun key-arg-fun (position-arg &key ((key-arg ka) "default-value" supplied-p))
(print position-arg)
(print ka))

in the definition, we build a certain relationship between the variable ka and the symbol key-arg, in this example, the symbol key-arg is interned into :cl-user, when we call this function in another package:

(defpackage :zhz
(:use :cl :cl-user))
(in-package :zhz)
(cl-user::key-arg-fun "zhz" 'cl-user::key-arg "messi")

we create a new relationship between the same symbol 'cl-user::key-arg and the value "messi", so the statement (print ka) can refer to the value through the symbol 'key-arg.

In shorter words: the symbol is kind like a bridge during the whole value reference, so we must use the same symbol, and the keyword package is a very convenient way to make this happen. Is this understanding correct?

Thanks and best regards,

Zhz

Kaz Kylheku

4/9/2015 2:57:00 PM

0

On 2015-04-09, zhz shi <messi.shizz@gmail.com> wrote:
> Hi all,
>
> I'm a newbie to common lisp and I know symbol is the key idea behind the
> whole language(and all LISP), but sometimes I found myself are really
> confused about it.
>
> Like this loop code snippet: (loop for i from 1 to 10 collect i), which will
> cause 5 symbols created and interned into current package(FOR, I, FROM, TO,
> COLLECT). (loop :for i :from 1 :to 10 :collect i) will intern related
> keywords in KEYWORD package.
Note that the ability to use symbols FOR, FROM, TO and COLLECT from any package
is a special feature of the LOOP macro only.

It allows you to use LOOP in any package without importing these clause symbols.
Without this feature, you would have to write:

(loop cl:for i cl:from ... cl:collect i)

assuming that CL:LOOP is visible in the current package, but CL:FOR and the
others are not.

There isn't anything wrong with making people import these, but somewhere
along the line, someone made the design decision to make the LOOP clause
identifiers behave as character strings rather than symbols.

Keywords could have been used. Then the syntax would have to be:

(loop :for i :from 1 :to 10 :collect i)

the designer apparently didn't like this.

> Could anybody kindly explain to me why CL is
> implemented this way? Is this a sort of pollution to packages(current package
> or keyword package) ?

Interning is essential because that's what identifies two occurrences of
a symbol in the same program as being the same object.

All programming languages perform interning in some form. C compilers do
interning. If you have:

{ int x = 3; ... foo(x); }

the x has to be entered into some symbol table in the compiler, so
the definition of x is properly connected to its later use.

That symbol table entry is likely retained throughout various compilation
passes, and optionally even into run-time (in the form of debugging info).

> Another is about the KEYWORD package, why is there a need of package KERWORD
> in cl?

The keyword package is useful because keywords have a special evaluation rule.
They evaluate to themselves.

If you invent a keyword symbol like :foo, you instantly get a token that you
can use throughout your program, such that all occurrences of that token refer
to the same symbol object. When that object is treated as a form to be evaluated,
it evaluates to that object itself: the same behavior as the forms 42 or "abc".

Other symbols, except for NIL and T (CL:NIL and CL:T) do not evaluate to themselves;
they are expected to denote variable bindings.

But why don't we just use the ' quote on regular symbols? If we want FOO to
evaluate to itself we can just use (QUOTE FOO) and write it as 'FOO which
is just as short as :FOO.

But with :FOO we have:

:foo -> :foo ;; foo evaluates to itself
(first '(:foo)) -> :foo ;; foo in a list is just itself

Whereas:

(defvar x 3)

x -> 3 ;; x evaluates to variable value via binding
(first '(x)) -> x ;; x in a list is itself

Self-evaluation is different from a quote operator!


> From HyperSpec it says "This makes it notationally convenient to use
> keywords when communicating between programs in different packages.", so what
> is the essential meaning of "communicating between programs in different
> packages"?

This is because :foo is a fully qualified symbol; it is a shorthand for KEYWORD:FOO.
So the meaning of :foo is the same no matter in what context it is read by
the Lisp reader, and it denotes the same thing everywhere.

If I write this function MYPACKAGE:

(defun fun (&key xyz))

you have to call that as (mypackage::fun ...) unless you make that more convenient
by bringing the symbol into the your package. But the keyword argument is just :xyz
just: (mypackage::fun :xyz 42).

Keywords are not just for communicating keyword arguments. Keywords give you a
supply of unique names for denoting properties, and members of sets and such.

C:

enum ice_cream_flavor { VANILLA, CHOCOLATE, ... } f = VANILLA;

switch (f) {
case VANILLA: ...
case CHOCOLATE: ...
...
}

Lisp:

(let ((f :vanilla))

...

(case f
(:vanilla ...)
(:chocolate ...)))

The difference is that keywords do not have numeric values (they are not an
enumeration); they are their own values, and we don't have a type "ice cream
flavor" which consists of a restricted subset of keywords.

Of course, we can define one.

;; the ice-cream-flavor type consists of three elements denoted by keywords:

(deftype ice-cream-flavor () '(member :vanilla :chocolate :strawberry))

;; check that the value of variable x is an ice-cream-flavor:
(check-type x ice-cream-flavor) ;; signals error

We could use non-keyword symbols. But the drawbacks are: knowing when to quote
and not to quote; and lack of visual distinction.

;; no quotes here
(deftype ice-cream-flavor () '(member vanilla chocolate strawberry))

(let ((x 'vanilla)) ;; quote here
;; ...
(case x
(vanilla ...) ;; no quote on CASE constants
((chocolate strawberry) ...)))

About the visual distinction, you know that if you see (:chocolate :strawberry)
then that is just keywords, and not a function call or any other syntax. Your
text editor can easily apply special syntax coloring to keywords, too.

Pascal J. Bourguignon

4/9/2015 4:23:00 PM

0

zhz shi <messi.shizz@gmail.com> writes:

> On Thursday, April 9, 2015 at 3:49:36 PM UTC+8, informatimago wrote:
>> Oh, and I wanted also to mention another consideration:
>>
>> Not all symbols used in sources are kept along when you compile it, far
>> from it.
>>
>> Only the quoted symbols and the globally bound are forwarded from the
>> compilation environment to the run-time environment.
>>
>> Therefore when you compile a file such as:
>>
>> (defpackage "EX3"
>> (:use "CL")
>> (:export "P"))
>> (in-package "EX3")
>> (defun p (x)
>> (loop for i below x sum (* i i)))
>>
>> and later load the compiled file (in a different image):
>>
>> cl-user> (load "/tmp/ex3.lx64fsl")
>> #P"/tmp/ex3.lx64fsl"
>>
>> Only the exported symbols and a few other symbols useful for debugging
>> and backtraces remain:
>>
>> cl-user> (do-symbols (s (find-package "EX3"))
>> (unless (eql (symbol-package s) (load-time-value (find-package "CL")))
>> (print s)))
>>
>> ex3:p
>> ex3::i
>> ex3::x
>> nil
>>
>> You could even expect that when compiled with (optimize (debug 0)), some
>> implementation would throw away I and X too.
>>
>> --
>> __Pascal Bourguignon__ http://www.informat...
>> "The factory of the future will have only two employees, a man and a
>> dog. The man will be there to feed the dog. The dog will be there to
>> keep the man from touching the equipment." -- Carl Bass CEO Autodesk
>
> Thanks for your explanation all answers from other guys, it's very
> useful info for me :-) :-)
>
> However, I still don't know why we must pass the same symbol to the
> function when using &key arguments. :(
>
> My guess is, when we define a function with &key argument:
>
> (in-package :cl-user)
> (defun key-arg-fun (position-arg &key ((key-arg ka) "default-value" supplied-p))
> (print position-arg)
> (print ka))
>
> in the definition, we build a certain relationship between the
> variable ka and the symbol key-arg, in this example, the symbol
> key-arg is interned into :cl-user, when we call this function in
> another package:
>
> (defpackage :zhz
> (:use :cl :cl-user))
> (in-package :zhz)
> (cl-user::key-arg-fun "zhz" 'cl-user::key-arg "messi")
>
> we create a new relationship between the same symbol 'cl-user::key-arg
> and the value "messi", so the statement (print ka) can refer to the
> value through the symbol 'key-arg.
>
> In shorter words: the symbol is kind like a bridge during the whole
> value reference, so we must use the same symbol, and the keyword
> package is a very convenient way to make this happen. Is this
> understanding correct?

No this is incorrect. The value is not accessed through the symbol
KEY-ARG. The symbol KEY-ARG is used to find the value to bind to the
parameter KA in the parameter p-list.

&key implies &rest, and:

(defun key-arg-fun (position-arg &key ((key-arg ka) "default-value" supplied-p))
(print position-arg)
(print ka))

is equivalent to:

(defun key-arg-fun (position-arg &rest rest-parameters)
(destructuring-bind (&key ((key-arg ka) "default-value" supplied-p)) rest-parameters
(print position-arg)
(print ka)))

which is equivalent to:

(defun key-arg-fun (position-arg &rest rest-parameters)
(let* ((supplied-p t)
(ka (let ((kwd-arg-2950 (getf rest-parameters 'key-arg '(nil))))
(if (eq kwd-arg-2950 '(nil))
(progn (setq supplied-p nil)
"default-value")
kwd-arg-2950))))
(print position-arg)
(print ka)))

So you can see that KEY-ARG is only used to access the value in the
p-list REST-PARAMETERS, to be bound to the parameter KA.

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Barry Margolin

4/9/2015 5:01:00 PM

0

In article <ea22f29b-9990-4eb9-8392-bd8c350c6efa@googlegroups.com>,
zhz shi <messi.shizz@gmail.com> wrote:

> My guess is, when we define a function with &key argument:
>
> (in-package :cl-user)
> (defun key-arg-fun (position-arg &key ((key-arg ka) "default-value"
> supplied-p))
> (print position-arg)
> (print ka))
>
> in the definition, we build a certain relationship between the variable ka
> and the symbol key-arg, in this example, the symbol key-arg is interned into
> :cl-user, when we call this function in another package:
>
> (defpackage :zhz
> (:use :cl :cl-user))
> (in-package :zhz)
> (cl-user::key-arg-fun "zhz" 'cl-user::key-arg "messi")
>
> we create a new relationship between the same symbol 'cl-user::key-arg and
> the value "messi", so the statement (print ka) can refer to the value through
> the symbol 'key-arg.
>
> In shorter words: the symbol is kind like a bridge during the whole value
> reference, so we must use the same symbol, and the keyword package is a very
> convenient way to make this happen. Is this understanding correct?

That's basically correct. You're just using the CL-USER package in place
of the KEYWORD package.

Keywords are a convenience feature. They have a terse syntax, because
you can abbreviate them as :KEY-ARG instead of having to spell out the
package name and quote it. It's a common repository of all these linking
symbols.

The package system exists to prevent different applications from
interfering with each other when they try to define variables or
functions with the same name. But the way keywords are used, there's
usually not a problem with conflicts like this. It doesn't usually
matter if two unrelated functions both take the same keyword arguments.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

taruss

4/10/2015 1:21:00 AM

0

On Thursday, April 9, 2015 at 10:01:03 AM UTC-7, Barry Margolin wrote:
>
> The package system exists to prevent different applications from
> interfering with each other when they try to define variables or
> functions with the same name. But the way keywords are used, there's
> usually not a problem with conflicts like this. It doesn't usually
> matter if two unrelated functions both take the same keyword arguments.

And that property is largely because keywords evaluate to themselves.
Since you aren't allowed to set the value of a keyword symbol to anything else
it is effectively a constant, and the same constant in all contexts. So there
is no interaction between the use of this constant in multiple places.

Now, you can use keywords to name functions, but this would be considered
perverse by lisp programmers. So don't do it.

Zach Beane

4/10/2015 1:47:00 AM

0

taruss@google.com writes:

> Now, you can use keywords to name functions, but this would be considered
> perverse by lisp programmers. So don't do it.

I do it all the time, but it's for functions I plan to use interactively
in the REPL. I never put it into code that will be shared with another
person or application.

Zach