From: Andras Simon
Subject: reading symbols in a package
Date: 
Message-ID: <vcdvh3om57g.fsf@csusza.math.bme.hu>
I'd like to make a package PACK that defines and exports a function
FOO which reads sexprs from a file and does something with each
dependig on its CAR, which is a symbol (without package prefix).  I
want to use (pack:foo file) from different packages.  FOO has a big
CASE form,

(case (car item)
  ((one) (...))
  ((two) (...))
  ...
  (t (...)))

The keys get interned (?), so CASE ends up comparing PACK::ONE with
(car item) if I'm not in PACK.

Is there a way to define PACK (or FOO) so that this doesn't happen? 
I can imagine kludges like

(case (intern (car item) :pack) ...)

but this looks awful. I'm sure there's a better way.

Andras

From: Michael Kappert
Subject: Re: reading symbols in a package
Date: 
Message-ID: <38ABEED3.B9BEDE75@iitb.fhg.de>
Andras Simon wrote:
> 
> I'd like to make a package PACK that defines and exports a function
> FOO which reads sexprs from a file and does something with each
> dependig on its CAR, which is a symbol (without package prefix).  I
> want to use (pack:foo file) from different packages.  FOO has a big
> CASE form,
> 
> (case (car item)
>   ((one) (...))
>   ((two) (...))
>   ...
>   (t (...)))
> 
> The keys get interned (?), 

Yes.

> so CASE ends up comparing PACK::ONE with (car item) if I'm not in PACK.

You "are" not in any package, cf. a recent post by Eric Naggum.
You pass forms to the lisp reader, directly or indirectly. read interns any 
symbols it encounters to the package wich is the current value of *package*. 

So the trick is to bind *package* to PACK just before calling read:

(let ((*package* (find-package "PACK")))
  (loop for item = (read <file> nil nil) while item do
    (case (car item)
      ... )))


Michael
  
 
-- 
Michael Kappert
Fraunhofer IITB
Fraunhoferstr. 1                                       Phone: +49(0)721/6091-477
D-76131 Karlsruhe, Germany                             EMail: ···@iitb.fhg.de
From: Andras Simon
Subject: Re: reading symbols in a package
Date: 
Message-ID: <vcd66vnd168.fsf@csusza.math.bme.hu>
Michael Kappert <···@iitb.fhg.de> writes:

> You "are" not in any package, cf. a recent post by Eric Naggum.
> You pass forms to the lisp reader, directly or indirectly. read interns any 
> symbols it encounters to the package wich is the current value of *package*. 
> 
> So the trick is to bind *package* to PACK just before calling read:
> 
> (let ((*package* (find-package "PACK")))
>   (loop for item = (read <file> nil nil) while item do
>     (case (car item)
> 	... )))


Thanks for your suggestion & correction.

I was hoping that there was a way to resolve this package problem the
other way round, ie., by somehow stripping the package prefix from the
keys. This would be nice because then I could further process what I
read from the file in yet another package (which also has lots of
CASEs). (I realize I should've stated my question accordingly.)  But
I'm probably better off doing the whole thing in one package.

Thanks again,
Andras
From: Coby Beck
Subject: Re: reading symbols in a package
Date: 
Message-ID: <950819977762@NewsSIEVE.cs.bonn.edu>
> > So the trick is to bind *package* to PACK just before calling read:
> >
> > (let ((*package* (find-package "PACK")))
> >   (loop for item = (read <file> nil nil) while item do
> >     (case (car item)
> > ... )))

Jumping in the middle of this discussion, but isn't this code creating a new
*package* variable?  It will not alter the global *package* value.  And just
a general thought:  if you are changing something that matters to forces
beyond your control, you had better preserve its previous value and but it
back the way you found it!  (that comes from general programming practice
concerns and not from any particular knowledge of how packages work in
lisp...maybe i'm off the track)

Coby
From: Robert Munyer
Subject: Re: reading symbols in a package
Date: 
Message-ID: <88hum0$5i8$5@eve.enteract.com>
Michael Kappert <···@iitb.fhg.de> wrote:
> > > So the trick is to bind *package* to PACK just before calling read:
> > >
> > > (let ((*package* (find-package "PACK")))
> > >   (loop for item = (read <file> nil nil) while item do
> > >     (case (car item)
> > > ... )))

In article <············@NewsSIEVE.cs.bonn.edu>,
Coby Beck <·····@mercury.bc.ca> wrote:
> Jumping in the middle of this discussion, but isn't this code
> creating a new *package* variable?  It will not alter the global
> *package* value.

*PACKAGE* is declared "special," so its binding has indefinite
scope.  The LET form above does indeed alter the globally accessible
value of *package* (temporarily) and then restores it automatically.


> And just a general thought:  if you are changing something that
> matters to forces beyond your control, you had better preserve
> its previous value and but it back the way you found it!

Yes, that's exactly what Michael's LET form does.


> (that comes from general programming practice concerns and not
> from any particular knowledge of how packages work in lisp...maybe
> i'm off the track)

Yes, that's good programming advice.  One of the advantages of
Lisp is that it often does this for you automatically.  Java
programmers (for example) seem to have to write an awful lot of
"try ... finally" stuff, in situations where Lisp programmers
wouldn't have to.

-- Robert Munyer <······@mcs.com>
From: Joe Marshall
Subject: Re: reading symbols in a package
Date: 
Message-ID: <DBZq4.40105$vi4.97243@dfw-read.news.verio.net>
Coby Beck <·····@mercury.bc.ca> wrote in message
·················@NewsSIEVE.cs.bonn.edu...
>
> > > So the trick is to bind *package* to PACK just before calling read:
> > >
> > > (let ((*package* (find-package "PACK")))
> > >   (loop for item = (read <file> nil nil) while item do
> > >     (case (car item)
> > > ... )))
>
> Jumping in the middle of this discussion, but isn't this code creating a
new
> *package* variable?  It will not alter the global *package* value.

You might think so, but Common Lisp allows you to declare a variable to
be `special'.  Special variables are dynamically bound, so the global
*package* value will be temporarily changed during the execution of
the body of the let statement.

That's not evident from the fragment above because the special declaration
of *package* is handled elsewhere.  You just have to be psychic.  However,
there is a convention of putting `*' around special variables.

> And just
> a general thought:  if you are changing something that matters to forces
> beyond your control, you had better preserve its previous value and but it
> back the way you found it!

Yes.  When you bind a special variable with LET (or lambda, for that
matter),
the value will be magically restored when the LET finishes, even if you
generate an error or throw an exception.
From: Coby Beck
Subject: Re: reading symbols in a package
Date: 
Message-ID: <950832155171@NewsSIEVE.cs.bonn.edu>
Erik Naggum <····@naggum.no> wrote in message
·····················@naggum.no...
> * "Coby Beck" <·····@mercury.bc.ca>
> | Jumping in the middle of this discussion, but isn't this code creating a
new
> | *package* variable?
>
>   no.  it's creating a new binding for an existing variable, whose binding
>   is said to be "special".  in effect, they are global variables with a
>   stack of values whose top-most value is the one used.  a binding pushes
>   (and an unbinding pops) a value on this stack, while an assignment would
>   change the top-most value.  the latter is considered rude and bad style.
>
> | It will not alter the global *package* value.
>
>   anyone who references *PACKAGE* within the dynamic scope of this binding
>   will see the new value.  (the old _value_ will never be altered this
>   way.)  it will therefore _appear_ that the global value has changed.
>
> | And just a general thought:  if you are changing something that matters
> | to forces beyond your control, you had better preserve its previous
value
> | and but it back the way you found it!
>
>   precisely.  that's why we use Common Lisp, where this is a supported and
>   safe language feature, and not some infeior language where the
programmer
>   has to do this stunt by himself.
>
> | (that comes from general programming practice concerns and not from any
> | particular knowledge of how packages work in lisp...maybe i'm off the
> | track)
>
>   yes, you are.  it is also completely unrelated to packages, but instead
>   related to how binding variables work in Lisp.  it is different from
most
>   other languages in ways that you will probably appreciate highly.
>
> #:Erik

And i do!  The more i learn the more i like...

cb
From: Barry Margolin
Subject: Re: reading symbols in a package
Date: 
Message-ID: <bWZq4.19$pO2.1015@burlma1-snr2>
In article <···············@csusza.math.bme.hu>,
Andras Simon  <······@math.bme.hu> wrote:
>I was hoping that there was a way to resolve this package problem the
>other way round, ie., by somehow stripping the package prefix from the
>keys. This would be nice because then I could further process what I
>read from the file in yet another package (which also has lots of
>CASEs). (I realize I should've stated my question accordingly.)  But
>I'm probably better off doing the whole thing in one package.

If you compare symbols using STRING-EQUAL it will compare the names rather
than the symbols themselves.  You won't be able to use CASE, you'll have to
write a big COND instead.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Paul Foley
Subject: Re: reading symbols in a package
Date: 
Message-ID: <m2hff7h0d4.fsf@mycroft.actrix.gen.nz>
On Thu, 17 Feb 2000 21:41:28 GMT, Barry Margolin wrote:

> Andras Simon  <······@math.bme.hu> wrote:
>> I was hoping that there was a way to resolve this package problem the
>> other way round, ie., by somehow stripping the package prefix from the
>> keys. This would be nice because then I could further process what I
>> read from the file in yet another package (which also has lots of
>> CASEs). (I realize I should've stated my question accordingly.)  But
>> I'm probably better off doing the whole thing in one package.

> If you compare symbols using STRING-EQUAL it will compare the names rather
> than the symbols themselves.  You won't be able to use CASE, you'll have to
> write a big COND instead.

I tried to email this to the original poster yesterday, but it's still 
sitting in my sendmail queue:

The obvious way would be to bind *PACKAGE* around the invocation of
READ, since you're doing the read in FOO, so that the newly-read
symbols will also be interned in PACK.  [It doesn't actually matter
where you call READ, but you probably don't want to force users of
your code to do this]

Alternatively, use a version of CASE that compares symbols based on
their name:

(defun eqs (x y)
  (or (eq x y)
      (and (symbolp x) (symbolp y) (string= (symbol-name x) (symbol-name y)))))

(defmacro scase (keyform &body cases)
  (let ((key (gensym)))
    `(let ((,key ,keyform))
       (declare (ignorable ,key))
       (cond ,@(loop for (test . body) in cases
                  when test
                  collect (cond ((consp test)
                                 `((member ,key ',test :test #'eqs) ,@body))
                                ((or (eq test 'otherwise) (eq test 't))
                                 `(t ,@body))
                                (t
                                 `((eqs ,key ',test) ,@body))))))))

-- 
Nomina stultorum in parietibus et portis semper videmus.      -- Cicero

(setq reply-to
  (concatenate 'string "Paul Foley " "<mycroft" '(··@) "actrix.gen.nz>"))
From: Robert Munyer
Subject: Re: reading symbols in a package
Date: 
Message-ID: <88hug1$5i8$3@eve.enteract.com>
In article <···············@csusza.math.bme.hu>,
Andras Simon <······@math.bme.hu> wrote:

> I was hoping that there was a way to resolve this package problem
> the other way round, ie., by somehow stripping the package prefix
> from the keys.

In memory, the package isn't really a prefix; it's more like a
container.  It only looks like a prefix when the symbol is printed.
The way to "strip the package" from a symbol is to get the symbol's
name, as a string, with SYMBOL-NAME.  Then you can re-intern the
name in some other package, or just continue using it as a string.


> This would be nice because then I could further process what I
> read from the file in yet another package (which also has lots
> of CASEs). (I realize I should've stated my question accordingly.)
> But I'm probably better off doing the whole thing in one package.

I don't know exactly what you're trying to do, but maybe you
shouldn't be dealing with packages at all.  Consider these suggestions:

Suggestion #1:  You've been calling these symbols "keys;" maybe
you should just make them all keywords (i. e. symbols in the
"keyword" package).  It's easy to read a symbol into the keyword
package, regardless of what package happens to be current, just by
putting a colon before the symbol in your input file.

Suggestion #2:  Don't use symbols at all.  Use strings, and keep
them in a hash table, and use GETHASH instead of CASE.

-- Robert Munyer <······@mcs.com>