From: ·········@gmail.com
Subject: CASE with symbol evaluating to list?
Date: 
Message-ID: <c37dfb7a-45e6-4eec-adb3-61401eb0b096@k1g2000prb.googlegroups.com>
I run into some difficulties with the CASE macro when I attempt to use
a constant as key. That constant evaluates as lists, but still the
CASE macro doesn't recognize it as list designator.

--8<--
CL-USER> (defconstant +mylist+ '(1 2 3))
+MYLIST+
CL-USER> (case 2 (+mylist+ (format t "~&found~%")) (otherwise (format
t "~&not found~%")))
not found
NIL
-->8--

which is fairly confusing (for a bloody beginner like me), since
--8<--
CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
"~&not found~%")))
found
NIL
CL-USER> (equal +mylist+ '(1 2 3))
T
CL-USER>
-->8--

Assuming the list I like CASE to search through is quite large and is
used multiple times - how would I do that?
I'd think some macro expanding to a proper list at compile time should
do, but so far I was not able to beat the CASE macro.

Any suggestions?

From: Thomas M. Hermann
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <4449ce24-4141-4e4b-ada0-4725e595db77@t3g2000yqa.googlegroups.com>
On Nov 22, 8:02 pm, ·········@gmail.com wrote:
> I run into some difficulties with the CASE macro when I attempt to use
> a constant as key. That constant evaluates as lists, but still the
> CASE macro doesn't recognize it as list designator.
>
> --8<--
> CL-USER> (defconstant +mylist+ '(1 2 3))
> +MYLIST+
> CL-USER> (case 2 (+mylist+ (format t "~&found~%")) (otherwise (format
> t "~&not found~%")))
> not found
> NIL
> -->8--
>
> which is fairly confusing (for a bloody beginner like me), since
> --8<--
> CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
> "~&not found~%")))
> found
> NIL
> CL-USER> (equal +mylist+ '(1 2 3))
> T
> CL-USER>
> -->8--
>
> Assuming the list I like CASE to search through is quite large and is
> used multiple times - how would I do that?
> I'd think some macro expanding to a proper list at compile time should
> do, but so far I was not able to beat the CASE macro.
>
> Any suggestions?

CASE is a macro, so it helps to use MACROEXPAND to see exactly what is
going on.

(macroexpand
 '(case 2
   (+mylist+ (format t "~&found~%"))
   (otherwise (format t "~&not found~%"))))

(LET ((#:G736 2))
  (DECLARE (IGNORABLE #:G736))
  (COND ((EQL #:G736 '+MYLIST+) NIL (FORMAT T "~&found~%"))
        (T NIL (FORMAT T "~&not found~%"))))

Note that when expanded, +MYLIST+ is quoted, it's not evaluated. Look
at the Hyperspec for CASE.

http://www.lispworks.com/documentation/HyperSpec/Body/m_case_.htm

Specifically, the normal-clause. normal-clause::= (keys form*)

The keys for case are designators for a list of objects.

list designator n. a designator for a list of objects; that is, an
object that denotes a list and that is one of: a non-nil atom
(denoting a singleton list whose element is that non-nil atom) or a
proper list (denoting itself).

Look at what CASE expands to when (1 2 3) are provided for the keys.

(macroexpand '(case 2
	       ((1 2 3) (format t "~&found~%"))
	       (otherwise (format t "~&not found~%"))))

(LET ((#:G739 2))
  (DECLARE (IGNORABLE #:G739))
  (COND
    ((OR (EQL #:G739 '1) (EQL #:G739 '2) (EQL #:G739 '3)) NIL
     (FORMAT T "~&found~%"))
    (T NIL (FORMAT T "~&not found~%"))))

So, you need to wrap CASE in your own macro that would evaluate +MYLIST
+. But, it makes more sense to use COND or IF as already suggested.

Tom
From: Tamas K Papp
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <6ot60cF574ouU1@mid.individual.net>
On Sat, 22 Nov 2008 20:17:21 -0800, Thomas M. Hermann wrote:

> On Nov 22, 8:02 pm, ·········@gmail.com wrote:
>> I run into some difficulties with the CASE macro when I attempt to use
>> a constant as key. That constant evaluates as lists, but still the CASE
>> macro doesn't recognize it as list designator.
>>
>> --8<--
>> CL-USER> (defconstant +mylist+ '(1 2 3)) +MYLIST+
>> CL-USER> (case 2 (+mylist+ (format t "~&found~%")) (otherwise (format t
>> "~&not found~%")))
>> not found
>> NIL
>> -->8--
>>
>> which is fairly confusing (for a bloody beginner like me), since --8<--
>> CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
>> "~&not found~%")))
>> found
>> NIL
>> CL-USER> (equal +mylist+ '(1 2 3))
>> T
>> CL-USER>
>> -->8--
>>
>> Assuming the list I like CASE to search through is quite large and is
>> used multiple times - how would I do that? I'd think some macro
>> expanding to a proper list at compile time should do, but so far I was
>> not able to beat the CASE macro.
>>
>> Any suggestions?
> 
> CASE is a macro, so it helps to use MACROEXPAND to see exactly what is
> going on.
> 
> (macroexpand
>  '(case 2
>    (+mylist+ (format t "~&found~%"))
>    (otherwise (format t "~&not found~%"))))
> 
> (LET ((#:G736 2))
>   (DECLARE (IGNORABLE #:G736))
>   (COND ((EQL #:G736 '+MYLIST+) NIL (FORMAT T "~&found~%"))
>         (T NIL (FORMAT T "~&not found~%"))))
> 
> Note that when expanded, +MYLIST+ is quoted, it's not evaluated. Look at
> the Hyperspec for CASE.
> 
> http://www.lispworks.com/documentation/HyperSpec/Body/m_case_.htm
> 
> Specifically, the normal-clause. normal-clause::= (keys form*)
> 
> The keys for case are designators for a list of objects.
> 
> list designator n. a designator for a list of objects; that is, an
> object that denotes a list and that is one of: a non-nil atom (denoting
> a singleton list whose element is that non-nil atom) or a proper list
> (denoting itself).
> 
> Look at what CASE expands to when (1 2 3) are provided for the keys.
> 
> (macroexpand '(case 2
> 	       ((1 2 3) (format t "~&found~%"))
> 	       (otherwise (format t "~&not found~%"))))
> 
> (LET ((#:G739 2))
>   (DECLARE (IGNORABLE #:G739))
>   (COND
>     ((OR (EQL #:G739 '1) (EQL #:G739 '2) (EQL #:G739 '3)) NIL
>      (FORMAT T "~&found~%"))
>     (T NIL (FORMAT T "~&not found~%"))))
> 
> So, you need to wrap CASE in your own macro that would evaluate +MYLIST
> +. But, it makes more sense to use COND or IF as already suggested.

I thought that +mylist+ as a symbol-macro would would work, but it does 
not get expanded.  Would somebody explain why?

Thanks,

Tamas
From: Wade
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <f742d33e-9f6b-4937-a542-3743f2e0e43f@v42g2000yqv.googlegroups.com>
On Nov 23, 7:00 am, Tamas K Papp <······@gmail.com> wrote:
> On Sat, 22 Nov 2008 20:17:21 -0800, Thomas M. Hermann wrote:
> > On Nov 22, 8:02 pm, ·········@gmail.com wrote:
> >> I run into some difficulties with the CASE macro when I attempt to use
> >> a constant as key. That constant evaluates as lists, but still the CASE
> >> macro doesn't recognize it as list designator.
>
> >> --8<--
> >> CL-USER> (defconstant +mylist+ '(1 2 3)) +MYLIST+
> >> CL-USER> (case 2 (+mylist+ (format t "~&found~%")) (otherwise (format t
> >> "~&not found~%")))
> >> not found
> >> NIL
> >> -->8--
>
> >> which is fairly confusing (for a bloody beginner like me), since --8<--
> >> CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
> >> "~&not found~%")))
> >> found
> >> NIL
> >> CL-USER> (equal +mylist+ '(1 2 3))
> >> T
> >> CL-USER>
> >> -->8--
>
> >> Assuming the list I like CASE to search through is quite large and is
> >> used multiple times - how would I do that? I'd think some macro
> >> expanding to a proper list at compile time should do, but so far I was
> >> not able to beat the CASE macro.
>
> >> Any suggestions?
>
> > CASE is a macro, so it helps to use MACROEXPAND to see exactly what is
> > going on.
>
> > (macroexpand
> >  '(case 2
> >    (+mylist+ (format t "~&found~%"))
> >    (otherwise (format t "~&not found~%"))))
>
> > (LET ((#:G736 2))
> >   (DECLARE (IGNORABLE #:G736))
> >   (COND ((EQL #:G736 '+MYLIST+) NIL (FORMAT T "~&found~%"))
> >         (T NIL (FORMAT T "~&not found~%"))))
>
> > Note that when expanded, +MYLIST+ is quoted, it's not evaluated. Look at
> > the Hyperspec for CASE.
>
> >http://www.lispworks.com/documentation/HyperSpec/Body/m_case_.htm
>
> > Specifically, the normal-clause. normal-clause::= (keys form*)
>
> > The keys for case are designators for a list of objects.
>
> > list designator n. a designator for a list of objects; that is, an
> > object that denotes a list and that is one of: a non-nil atom (denoting
> > a singleton list whose element is that non-nil atom) or a proper list
> > (denoting itself).
>
> > Look at what CASE expands to when (1 2 3) are provided for the keys.
>
> > (macroexpand '(case 2
> >           ((1 2 3) (format t "~&found~%"))
> >           (otherwise (format t "~&not found~%"))))
>
> > (LET ((#:G739 2))
> >   (DECLARE (IGNORABLE #:G739))
> >   (COND
> >     ((OR (EQL #:G739 '1) (EQL #:G739 '2) (EQL #:G739 '3)) NIL
> >      (FORMAT T "~&found~%"))
> >     (T NIL (FORMAT T "~&not found~%"))))
>
> > So, you need to wrap CASE in your own macro that would evaluate +MYLIST
> > +. But, it makes more sense to use COND or IF as already suggested.
>
> I thought that +mylist+ as a symbol-macro would would work, but it does
> not get expanded.  Would somebody explain why?
>


You might expect that +mylist+ would get expanded at read time
for a symbol-macro, but it gets expanded at macro-expand
time (just like regular macros.  So the symbol +mylist+ is given to
the CASE macro where it is inserted as a symbol (probably quoted).

See Hyperspec under define-symbol-macro

<quote>

Each global reference to symbol (i.e., not shadowed[2] by a binding
for a variable or symbol macro named by the same symbol) is expanded
by the normal macro expansion process; see Section 3.1.2.1.1 (Symbols
as Forms). The expansion of a symbol macro is subject to further macro
expansion in the same lexical environment as the symbol macro
reference, exactly analogous to normal macros.

</quote>

Then macro-expand time happens on the result of the CASE macro
and all its sees is (quote +mylist+) which is not to be expanded.

Wade
From: Pascal J. Bourguignon
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <87prkm1n2l.fsf@hubble.informatimago.com>
Tamas K Papp <······@gmail.com> writes:

> On Sat, 22 Nov 2008 20:17:21 -0800, Thomas M. Hermann wrote:
> [...]
>> Look at what CASE expands to when (1 2 3) are provided for the keys.
>> 
>> (macroexpand '(case 2
>> 	       ((1 2 3) (format t "~&found~%"))
>> 	       (otherwise (format t "~&not found~%"))))
>> 
>> (LET ((#:G739 2))
>>   (DECLARE (IGNORABLE #:G739))
>>   (COND
>>     ((OR (EQL #:G739 '1) (EQL #:G739 '2) (EQL #:G739 '3)) NIL
>>      (FORMAT T "~&found~%"))
>>     (T NIL (FORMAT T "~&not found~%"))))
>> 
>> So, you need to wrap CASE in your own macro that would evaluate +MYLIST
>> +. But, it makes more sense to use COND or IF as already suggested.
>
> I thought that +mylist+ as a symbol-macro would would work, but it does 
> not get expanded.  Would somebody explain why?

Because the key may be whatever it wants, it won't get evaluated by CASE!


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
From: Wade
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <b5c21883-488f-4178-b5c1-44b3b7729122@3g2000yqs.googlegroups.com>
On Nov 22, 7:02 pm, ·········@gmail.com wrote:
> I run into some difficulties with the CASE macro when I attempt to use
> a constant as key. That constant evaluates as lists, but still the
> CASE macro doesn't recognize it as list designator.
>
> --8<--
> CL-USER> (defconstant +mylist+ '(1 2 3))
> +MYLIST+
> CL-USER> (case 2 (+mylist+ (format t "~&found~%")) (otherwise (format
> t "~&not found~%")))
> not found
> NIL
> -->8--
>
> which is fairly confusing (for a bloody beginner like me), since
> --8<--
> CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
> "~&not found~%")))
> found
> NIL
> CL-USER> (equal +mylist+ '(1 2 3))
> T
> CL-USER>
> -->8--
>
> Assuming the list I like CASE to search through is quite large and is
> used multiple times - how would I do that?
> I'd think some macro expanding to a proper list at compile time should
> do, but so far I was not able to beat the CASE macro.
>
> Any suggestions?

Common Problem, You can do...

(defconstant +mylist+ '(1 2 3))

(defun test (v)
  (case v
    (#.+mylist+ (format t "~&found~%"))
    (otherwise (format t "~&not found~%"))))

CL-USER> (test 2)
found
NIL

Wade
From: Tamas K Papp
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <6orsnrF54s82U1@mid.individual.net>
On Sat, 22 Nov 2008 18:02:08 -0800, guenthert wrote:

> I run into some difficulties with the CASE macro when I attempt to use a
> constant as key. That constant evaluates as lists, but still the CASE
> macro doesn't recognize it as list designator.
> 
> --8<--
> CL-USER> (defconstant +mylist+ '(1 2 3)) +MYLIST+
> CL-USER> (case 2 (+mylist+ (format t "~&found~%")) (otherwise (format t
> "~&not found~%")))
> not found
> NIL
> -->8--
> 
> which is fairly confusing (for a bloody beginner like me), since --8<--
> CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
> "~&not found~%")))
> found
> NIL
> CL-USER> (equal +mylist+ '(1 2 3))
> T
> CL-USER>
> -->8--
> 
> Assuming the list I like CASE to search through is quite large and is
> used multiple times - how would I do that? I'd think some macro
> expanding to a proper list at compile time should do, but so far I was
> not able to beat the CASE macro.
> 
> Any suggestions?

I can't think of anything.  But why do you need to use case?  Why not
(find 2 +mylist+), and a cond/if around it?

Tamas
From: ·········@gmail.com
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <2edc4189-9a8d-4c3f-a552-264fff72c65b@40g2000prx.googlegroups.com>
On Nov 22, 6:16 pm, Tamas K Papp <······@gmail.com> wrote:
> On Sat, 22 Nov 2008 18:02:08 -0800, guenthert wrote:
> > I run into some difficulties with the CASE macro when I attempt to use a
> > constant as key. That constant evaluates as lists, but still the CASE
> > macro doesn't recognize it as list designator.
>
> > --8<--
> > CL-USER> (defconstant +mylist+ '(1 2 3)) +MYLIST+
> > CL-USER> (case 2 (+mylist+ (format t "~&found~%")) (otherwise (format t
> > "~&not found~%")))
> > not found
> > NIL
> > -->8--
>
> > which is fairly confusing (for a bloody beginner like me), since --8<--
> > CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
> > "~&not found~%")))
> > found
> > NIL
> > CL-USER> (equal +mylist+ '(1 2 3))
> > T
> > CL-USER>
> > -->8--
>
> > Assuming the list I like CASE to search through is quite large and is
> > used multiple times - how would I do that? I'd think some macro
> > expanding to a proper list at compile time should do, but so far I was
> > not able to beat the CASE macro.
>
> > Any suggestions?
>
> I can't think of anything.  But why do you need to use case?  Why not
> (find 2 +mylist+), and a cond/if around it?
>
> Tamas

Oh, the list is not the only key in that case form, there are more.
COND came to my mind, but then I would have to explicitly state the
condition (keyform) multiple times. I'd think CL can do better.
From: Thomas M. Hermann
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <d1bb5df7-1def-49a1-869a-64056b542063@l42g2000yqe.googlegroups.com>
On Nov 22, 10:13 pm, ·········@gmail.com wrote:
> On Nov 22, 6:16 pm, Tamas K Papp <······@gmail.com> wrote:
>
>
>
> > On Sat, 22 Nov 2008 18:02:08 -0800, guenthert wrote:
> > > I run into some difficulties with the CASE macro when I attempt to use a
> > > constant as key. That constant evaluates as lists, but still the CASE
> > > macro doesn't recognize it as list designator.
>
> > > --8<--
> > > CL-USER> (defconstant +mylist+ '(1 2 3)) +MYLIST+
> > > CL-USER> (case 2 (+mylist+ (format t "~&found~%")) (otherwise (format t
> > > "~&not found~%")))
> > > not found
> > > NIL
> > > -->8--
>
> > > which is fairly confusing (for a bloody beginner like me), since --8<--
> > > CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
> > > "~&not found~%")))
> > > found
> > > NIL
> > > CL-USER> (equal +mylist+ '(1 2 3))
> > > T
> > > CL-USER>
> > > -->8--
>
> > > Assuming the list I like CASE to search through is quite large and is
> > > used multiple times - how would I do that? I'd think some macro
> > > expanding to a proper list at compile time should do, but so far I was
> > > not able to beat the CASE macro.
>
> > > Any suggestions?
>
> > I can't think of anything.  But why do you need to use case?  Why not
> > (find 2 +mylist+), and a cond/if around it?
>
> > Tamas
>
> Oh, the list is not the only key in that case form, there are more.
> COND came to my mind, but then I would have to explicitly state the
> condition (keyform) multiple times. I'd think CL can do better.

In that case, use FIND or MEMBER and you can APPEND or CONCATENATE the
lists.
From: Barry Fishman
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <m3d4gmwhgn.fsf@barry_fishman.acm.org>
·········@gmail.com writes:
> Oh, the list is not the only key in that case form, there are more.
> COND came to my mind, but then I would have to explicitly state the
> condition (keyform) multiple times. I'd think CL can do better.

As others have said the case will not evaluate its "keys" arguments.
Since +mylist+ is constant you can use #. to evaluate it at read time.

(case 2
  (#.+mylist+ (format t "~&found~%"))
  (otherwise  (format t "~&not found~%")))

-- 
Barry Fishman
From: ·········@gmail.com
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <05e678f2-21e1-4072-8ecc-8d36dbf0a6bb@k36g2000pri.googlegroups.com>
On Nov 23, 8:11 am, Barry Fishman <·············@acm.org> wrote:
> ·········@gmail.com writes:
> > Oh, the list is not the only key in that case form, there are more.
> > COND came to my mind, but then I would have to explicitly state the
> > condition (keyform) multiple times. I'd think CL can do better.
>
> As others have said the case will not evaluate its "keys" arguments.
> Since +mylist+ is constant you can use #. to evaluate it at read time.
>
> (case 2
>   (#.+mylist+ (format t "~&found~%"))
>   (otherwise  (format t "~&not found~%")))
>
> --
> Barry Fishman

Yes #. was what I needed, thanks (and thank you Wade) for pointing
that out. I knew it must have been possible to force te evaluation of
the constant at read time (I better read up on all the other # macros
as well now). Thanks also to the others who offered alternative
solutions.
From: Thomas A. Russ
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <ymiod05wyv3.fsf@blackcat.isi.edu>
·········@gmail.com writes:

> Yes #. was what I needed, thanks (and thank you Wade) for pointing
> that out. I knew it must have been possible to force te evaluation of
> the constant at read time

Of course you now have to make sure that the constant is defined at read
time.  In particular, you won't be able to have the following things in
the same file and be guaranteed that they will work:

(defconstant +mylist+ '(1 2 3))

(case (#.+mylist+ ...))

Since the DEFCONSTANT form will not be evaluated at read time.

So you either need to define your constants in a separate file that gets
loaded (and thus evalutated) before you read the forms with the CASE
statements, or you have to arrange for the evaulation of the DEFCONSTANT
form in the read-time environment.  But that might not make it available
in the environment in which you load the code.

So if you were to put something like

#.(defconstant +mylist+ '(1 2 3))

in your file, you would not be able to refer to +mylist+ EXCEPT by using
the #. syntax.  At least not if you wanted to compile the file and then
just load the compiled version.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: ·········@gmail.com
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <d1b2fe43-cd5b-4490-8e77-9adeeec46f29@p2g2000prn.googlegroups.com>
On Nov 23, 8:07 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> ·········@gmail.com writes:
> > Yes #. was what I needed, thanks (and thank you Wade) for pointing
> > that out. I knew it must have been possible to force te evaluation of
> > the constant at read time
>
> Of course you now have to make sure that the constant is defined at read
> time.  In particular, you won't be able to have the following things in
> the same file and be guaranteed that they will work:
>
> (defconstant +mylist+ '(1 2 3))
>
> (case (#.+mylist+ ...))
>
> Since the DEFCONSTANT form will not be evaluated at read time.
>
> So you either need to define your constants in a separate file that gets
> loaded (and thus evalutated) before you read the forms with the CASE
> statements, or you have to arrange for the evaulation of the DEFCONSTANT
> form in the read-time environment.  But that might not make it available
> in the environment in which you load the code.
>
> So if you were to put something like
>
> #.(defconstant +mylist+ '(1 2 3))
>
> in your file, you would not be able to refer to +mylist+ EXCEPT by using
> the #. syntax.  At least not if you wanted to compile the file and then
> just load the compiled version.
>
> --
> Thomas A. Russ,  USC/Information Sciences Institute

If I understand [1] correctly, it's implementation dependent (sigh).

SBCL does thankfully what I would expect, due to
--8<--
CL-USER> (macroexpand '(defconstant +test+ 2))
(EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
  (SB-C::%DEFCONSTANT '+TEST+ 2 'NIL (SB-C:SOURCE-LOCATION)))
T
-->8--


[1] http://www.lispworks.com/documentation/HyperSpec/Issues/iss059_w.htm
From: Thomas A. Russ
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <ymir651otkh.fsf@blackcat.isi.edu>
·········@gmail.com writes:

> On Nov 23, 8:07��pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> > ·········@gmail.com writes:
> > > Yes #. was what I needed, thanks (and thank you Wade) for pointing
> > > that out. I knew it must have been possible to force te evaluation of
> > > the constant at read time
> >
> > Of course you now have to make sure that the constant is defined at read
> > time. ��In particular, you won't be able to have the following things in
> > the same file and be guaranteed that they will work:
> >
> > (defconstant +mylist+ '(1 2 3))
> >
> > (case (#.+mylist+ ...))
> >
> > Since the DEFCONSTANT form will not be evaluated at read time.
> >
> > So you either need to define your constants in a separate file that gets
> > loaded (and thus evalutated) before you read the forms with the CASE
> > statements, or you have to arrange for the evaulation of the DEFCONSTANT
> > form in the read-time environment. ��But that might not make it available
> > in the environment in which you load the code.
> >
> > So if you were to put something like
> >
> > #.(defconstant +mylist+ '(1 2 3))
> >
> > in your file, you would not be able to refer to +mylist+ EXCEPT by using
> > the #. syntax. ��At least not if you wanted to compile the file and then
> > just load the compiled version.
> >
> > --
> > Thomas A. Russ, ��USC/Information Sciences Institute
> 
> If I understand [1] correctly, it's implementation dependent (sigh).
> 
> SBCL does thankfully what I would expect, due to
> --8<--
> CL-USER> (macroexpand '(defconstant +test+ 2))
> (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
>   (SB-C::%DEFCONSTANT '+TEST+ 2 'NIL (SB-C:SOURCE-LOCATION)))
> T
> -->8--

Well, it's actually potentially worse than that.  There may not be any
(current) implementations that actually do this, but there isn't
anything in the Specification that would stop an implementation from
first reading the entire file and storing the resulting S-expressions,
and then taking a second pass to actually evaluate them.

If such an implementation existed, then a read-time evaluation would
fail, since the constant would not be defined when the reading was
done.  It would only be defined in the second pass, when the objects
that were read are processed.

Now this is perhaps more likely to happen during compilation than
loading, so you would have to be careful about compiling this code.
That said, it is perhaps likely that it would always succeed with an
appropriate EVAL-WHEN construction.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Tobias C. Rittweiler
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <87vdudc4sc.fsf@freebits.de>
···@sevak.isi.edu (Thomas A. Russ) writes:

> Well, it's actually potentially worse than that.  There may not be any
> (current) implementations that actually do this, but there isn't
> anything in the Specification that would stop an implementation from
> first reading the entire file and storing the resulting S-expressions,
> and then taking a second pass to actually evaluate them.

The package system (and the reader algorithm) do not allow such a
scheme. How else would IN-PACKAGE forms affect the *PACKAGE* later
symbols are interned in? 

It's also sort of explicitly mentioned in section 3.2.3.

  -T.
From: Kaz Kylheku
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <20081124125104.460@gmail.com>
On 2008-11-24, Thomas A. Russ <···@sevak.isi.edu> wrote:
> Well, it's actually potentially worse than that.  There may not be any
> (current) implementations that actually do this, but there isn't
> anything in the Specification that would stop an implementation from
> first reading the entire file and storing the resulting S-expressions,
> and then taking a second pass to actually evaluate them.

However, the fact that no current implementations do that ought to stop
any halfway sane implementor.

3.2.3 says that ``[s]uccessive forms are read from the file by compile-file
and processed in not-compile-time mode'', which is very suggestive of a
form-by-form processing.

Note that doing it the way you suggest would break basic package
manipulation.  If the file contains an IN-PACKAGE top-level form, that must be
processed by the compiler, because it affects how symbols are interned in the
remainder of the file.
From: William James
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <ggpqov$aoq$1@aioe.org>
Thomas A. Russ wrote:

> ·········@gmail.com writes:
> 
> > On Nov 23, 8:07 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> > > ·········@gmail.com writes:
> > > > Yes #. was what I needed, thanks (and thank you Wade) for
> > > > pointing that out. I knew it must have been possible to force
> > > > te evaluation of the constant at read time
> > > 
> > > Of course you now have to make sure that the constant is defined
> > > at read time.  In particular, you won't be able to have the
> > > following things in the same file and be guaranteed that they
> > > will work:
> > > 
> > > (defconstant +mylist+ '(1 2 3))
> > > 
> > > (case (#.+mylist+ ...))
> > > 
> > > Since the DEFCONSTANT form will not be evaluated at read time.
> > > 
> > > So you either need to define your constants in a separate file
> > > that gets loaded (and thus evalutated) before you read the forms
> > > with the CASE statements, or you have to arrange for the
> > > evaulation of the DEFCONSTANT form in the read-time environment.
> > > But that might not make it available in the environment in which
> > > you load the code.
> > > 
> > > So if you were to put something like
> > > 
> > > #.(defconstant +mylist+ '(1 2 3))
> > > 
> > > in your file, you would not be able to refer to +mylist+ EXCEPT
> > > by using the #. syntax.  At least not if you wanted to compile
> > > the file and then just load the compiled version.
> > > 
> > > --
> > > Thomas A. Russ,  USC/Information Sciences Institute
> > 
> > If I understand [1] correctly, it's implementation dependent (sigh).
> > 
> > SBCL does thankfully what I would expect, due to
> > --8<--
> > CL-USER> (macroexpand '(defconstant +test+ 2))
> > (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
> >   (SB-C::%DEFCONSTANT '+TEST+ 2 'NIL (SB-C:SOURCE-LOCATION)))
> > T
> > -->8--
> 
> Well, it's actually potentially worse than that.  There may not be any
> (current) implementations that actually do this, but there isn't
> anything in the Specification that would stop an implementation from
> first reading the entire file and storing the resulting S-expressions,
> and then taking a second pass to actually evaluate them.
> 
> If such an implementation existed, then a read-time evaluation would
> fail, since the constant would not be defined when the reading was
> done.  It would only be defined in the second pass, when the objects
> that were read are processed.
> 
> Now this is perhaps more likely to happen during compilation than
> loading, so you would have to be careful about compiling this code.
> That said, it is perhaps likely that it would always succeed with an
> appropriate EVAL-WHEN construction.


This whole thread is further proof, although none is needed,
that CL is crap.

You probably already deduced that from its monikers:
COBOL Lisp, Commune Lisp, and Committee Lisp.
From: Kaz Kylheku
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <20081124105841.738@gmail.com>
On 2008-11-24, Thomas A. Russ <···@sevak.isi.edu> wrote:
> ·········@gmail.com writes:
>
>> Yes #. was what I needed, thanks (and thank you Wade) for pointing
>> that out. I knew it must have been possible to force te evaluation of
>> the constant at read time
>
> Of course you now have to make sure that the constant is defined at read
> time.  In particular, you won't be able to have the following things in
> the same file and be guaranteed that they will work:
>
> (defconstant +mylist+ '(1 2 3))
>
> (case (#.+mylist+ ...))
>
> Since the DEFCONSTANT form will not be evaluated at read time.

There is a problem, but not for this reason. Under compilation, the DEFCONSTANT
form is indeed processed specially, and this happens before the next form is
read. In spite of that, +mylist+ is not necessarily available at read-time.

The compilation semantics for DEFCONSTANTS are stated as a requirement that the
compiler must recognize the given name a as a constant. That is not the same as
introducing the constant in a general way into its own environment.

> So you either need to define your constants in a separate file that gets
> loaded (and thus evalutated) before you read the forms with the CASE

If +mylist+, during compilation, is not recognized as a constant at read-time,
putting the form into a separate file that is LOAD-ed will not necessarily
solve the problem.

> statements, or you have to arrange for the evaulation of the DEFCONSTANT
> form in the read-time environment.  But that might not make it available
> in the environment in which you load the code.

The thing to do is to wrap the DEFCONSTANT in EVAL-WHEN:

  (eval-when (:compile-toplevel :load-toplevel)
    (defconstant +mylist+ '(1 2 3)))

Now the compiler must evaluate the form in its environment (compile-time-too
mode), making the constant available at read time for subsequent forms.
From: Tobias C. Rittweiler
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <87r650cfdj.fsf@freebits.de>
Kaz Kylheku <········@gmail.com> writes:

> The thing to do is to wrap the DEFCONSTANT in EVAL-WHEN:
>
>   (eval-when (:compile-toplevel :load-toplevel)
>     (defconstant +mylist+ '(1 2 3)))
>
> Now the compiler must evaluate the form in its environment (compile-time-too
> mode), making the constant available at read time for subsequent forms.

As you omitted :EXECUTE, the constant +MYLIST+ won't be available when
you just LOAD the source file without having run COMPILE-FILE on it
previously.

It's very rare that you want to omit a situation in EVAL-WHEN. Anyone
who wants to share his story? :-)

  -T.
From: Rainer Joswig
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <joswig-8949DC.11272725112008@news-europe.giganews.com>
In article <··············@freebits.de>,
 "Tobias C. Rittweiler" <···@freebits.de.invalid> wrote:

> Kaz Kylheku <········@gmail.com> writes:
> 
> > The thing to do is to wrap the DEFCONSTANT in EVAL-WHEN:
> >
> >   (eval-when (:compile-toplevel :load-toplevel)
> >     (defconstant +mylist+ '(1 2 3)))
> >
> > Now the compiler must evaluate the form in its environment (compile-time-too
> > mode), making the constant available at read time for subsequent forms.
> 
> As you omitted :EXECUTE, the constant +MYLIST+ won't be available when
> you just LOAD the source file without having run COMPILE-FILE on it
> previously.
> 
> It's very rare that you want to omit a situation in EVAL-WHEN. Anyone
> who wants to share his story? :-)
> 
>   -T.

A grep through Lispm sources shows (almost) all combinations of EVAL-WHEN.

But your remark highlights an interesting 'feature' of :load-toplevel.

As I understand it, :load-toplevel really means
 :load-toplevel-of-file-compiled-code .

So, as you mention, the code ONLY runs when a 'fasl' file
with compiled code is being loaded.
It does not run when a SOURCE file is loaded.

One for the list of 'traps' and 'pitfalls' of Common Lisp.

-- 
http://lispm.dyndns.org/
From: Rob Warnock
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <h8udnR_yaOt8ubfUnZ2dnUVZ_ojinZ2d@speakeasy.net>
<·········@gmail.com> wrote:
+---------------
| Barry Fishman <·············@acm.org> wrote:
| > As others have said the case will not evaluate its "keys" arguments.
| > Since +mylist+ is constant you can use #. to evaluate it at read time.
| >
| > (case 2
| >   (#.+mylist+ (format t "~&found~%"))
| >   (otherwise �(format t "~&not found~%")))
| 
| Yes #. was what I needed, thanks (and thank you Wade) for pointing
| that out. I knew it must have been possible to force te evaluation of
| the constant at read time ...
+---------------

But note that for that to work as you expect when compiling [rather
than playing around at the REPL], the definition of +MYLIST+ may have
to be inside an (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE) ...)
since some CLs don't automatically make DEFCONSTANT values visible
at compile time[1]. And conversely, if you do that then you will
pollute your compile-time environment with that symbol [which may
or may not cause problems].

As others have pointed out, CASE isn't really buying you anything
over COND in this situation. Using COND really would be better...


-Rob

[1] As is permitted by CLHS "Macro DEFCONSTANT":

      If a defconstant form appears as a top level form, the compiler must
      recognize that name names a constant variable. An implementation
      may choose to evaluate the value-form at compile time, load time,
      or both.

    The subtlety here is that the implementation is *permitted* to
    evaluate the value-form *only* at load time, and thus in the
    absence of an applicable EVAL-WHEN the value of the constant
    variable is *NOT* available at compile time. [At least one
    popular implementation does this.]

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Matthew D Swank
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <ESJWk.11$mo7.1@newsfe22.iad>
On Sun, 23 Nov 2008 11:11:04 -0500, Barry Fishman wrote:

> ·········@gmail.com writes:
>> Oh, the list is not the only key in that case form, there are more.
>> COND came to my mind, but then I would have to explicitly state the
>> condition (keyform) multiple times. I'd think CL can do better.
> 
> As others have said the case will not evaluate its "keys" arguments.
> Since +mylist+ is constant you can use #. to evaluate it at read time.
> 
> (case 2
>   (#.+mylist+ (format t "~&found~%"))
>   (otherwise  (format t "~&not found~%")))

Others have mentioned problems with +mylist+ being available at read 
time.  In addition using #. is dependent on *read-eval* being t.  Also 
using #. to get around cases semantics smells to me.  If cond is too 
verbose, define a macro or two:

(defmacro switch (keyform &body cases)
  "Switch is like case, except that it does not quote keys, and only 
accepts one key per case."
  (let ((k (gensym)))
    `(let ((,k ,keyform))
       ,(reduce (lambda (case rest)
		  (destructuring-bind (key &body forms) case
		    `(cond ((eql ,key ,k) ,@forms)
			   (t ,rest))))
		cases
		:from-end t
		:initial-value nil))))
 
(defmacro eswitch (keyform &body cases)
  "ESwitch is like ecase, except that it does not quote keys, and only 
accepts one key per case."
  (let ((k (gensym))
        (err 
         `(error "~a fell through ESWITCH expression. Wanted one of ~a"
                 ,k (list ,@(mapcar #'caar cases))))
        (cases (mapcar (lambda (case)
                         (destructuring-bind (key &body forms) case
                           (cons (list (gensym) key) forms)))
                       cases)))
    `(let ((,k ,keyform)
           ,@(mapcar #'car cases))
       ,(reduce (lambda (case rest)
		  (destructuring-bind ((key-val key) &body forms) case
                    (declare (ignore key))
		    `(cond ((eql ,key-val ,k) ,@forms)
			   (t ,rest))))
		cases
		:from-end t
		:initial-value err))))
	 

Might be a good start.


Matt
-- 
Keep emotionally active.  Cater to your favorite neurosis.
From: Matthew D Swank
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <k_JWk.12$mo7.6@newsfe22.iad>
On Tue, 25 Nov 2008 02:59:48 +0000, Matthew D Swank wrote:

> (defmacro eswitch (keyform &body cases)
>   "ESwitch is like ecase, except that it does not quote keys, and only
> accepts one key per case."
Should be:

(defmacro eswitch (keyform &body cases)
  "ESwitch is like ecase, except that it does not quote keys, and only
 accepts one key per case."
   (let* ((k (gensym))
          (cases (mapcar (lambda (case)
                           (destructuring-bind (key &body forms) case
                             (cons (list (gensym) key) forms)))
                         cases))
          (err
           `(error "~a fell through ESWITCH expression. Wanted one of ~a"
                   ,k (list ,@(mapcar #'caar cases)))))
     `(let ((,k ,keyform)
            ,@(mapcar #'car cases))
        ,(reduce (lambda (case rest)
 		  (destructuring-bind ((key-val key) &body forms) case
                     (declare (ignore key))
 		    `(cond ((eql ,key-val ,k) ,@forms)
 			   (t ,rest))))
 		cases
 		:from-end t
 		:initial-value err))))


-- 
The abuse of greatness is when it disjoins remorse from power.
		-- William Shakespeare, "Julius Caesar"
From: Pascal Costanza
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <6ot8slF5acf8U1@mid.individual.net>
·········@gmail.com wrote:
> On Nov 22, 6:16 pm, Tamas K Papp <······@gmail.com> wrote:
>> On Sat, 22 Nov 2008 18:02:08 -0800, guenthert wrote:
>>> I run into some difficulties with the CASE macro when I attempt to use a
>>> constant as key. That constant evaluates as lists, but still the CASE
>>> macro doesn't recognize it as list designator.
>>> --8<--
>>> CL-USER> (defconstant +mylist+ '(1 2 3)) +MYLIST+
>>> CL-USER> (case 2 (+mylist+ (format t "~&found~%")) (otherwise (format t
>>> "~&not found~%")))
>>> not found
>>> NIL
>>> -->8--
>>> which is fairly confusing (for a bloody beginner like me), since --8<--
>>> CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
>>> "~&not found~%")))
>>> found
>>> NIL
>>> CL-USER> (equal +mylist+ '(1 2 3))
>>> T
>>> CL-USER>
>>> -->8--
>>> Assuming the list I like CASE to search through is quite large and is
>>> used multiple times - how would I do that? I'd think some macro
>>> expanding to a proper list at compile time should do, but so far I was
>>> not able to beat the CASE macro.
>>> Any suggestions?
>> I can't think of anything.  But why do you need to use case?  Why not
>> (find 2 +mylist+), and a cond/if around it?
>>
>> Tamas
> 
> Oh, the list is not the only key in that case form, there are more.
> COND came to my mind, but then I would have to explicitly state the
> condition (keyform) multiple times. I'd think CL can do better.

Why? It can't get that much better than COND.

CASE and TYPECASE are primarily for optimization. COND has all the 
expressiveness you need.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Thomas A. Russ
Subject: Re: CASE with symbol evaluating to list?
Date: 
Message-ID: <ymiskphwz9n.fsf@blackcat.isi.edu>
·········@gmail.com writes:

> I run into some difficulties with the CASE macro when I attempt to use
> a constant as key. That constant evaluates as lists, but still the
> CASE macro doesn't recognize it as list designator.
[snip]
> --8<--
> CL-USER> (case 2 ((1 2 3) (format t "~&found~%")) (otherwise (format t
> "~&not found~%")))
> found
> NIL
> CL-USER> (equal +mylist+ '(1 2 3))
> T
> CL-USER>
> -->8--

The key to understanding this lies in noticing that in the CASE macro
you wrote (1 2 3) and in the EQUAL function you wrote '(1 2 3).  The
quote character is very significant, since it gives you the clue that
the list is evaluated in the second context but not in the first.

Since CASE does not evaluate its key forms, using the constant +my-list+
will give you the literal symbol +MYLIST+ as your key instead.  So the
correct corresponding EQUAL test would be

  (equal '+my-list+ '(1 2 3))   =>  NIL  (as you would expect)

> Assuming the list I like CASE to search through is quite large and is
> used multiple times - how would I do that?

Well, if you need evaulation you can either use COND instead, and then
have any test you want, or you can create your own case-like macro.  I
would think that the COND solution would be better, since the main
benefit of the CASE macro is really readability and that depends on the
keys being literals in the code.

So, the solution I like would look like

(let ((key (evaluate-key-form)))
  (cond ((find key +mylist+) ...)
        ...
        (t "Not found")))

-- 
Thomas A. Russ,  USC/Information Sciences Institute