Was reading the Hyperspec for CASE and was a bit stymied as to what
conditional test it uses to make its comparisons. Specifically, the spec
just says:
"Each of the normal-clauses is then considered in turn. If the test-key is
the same as any key for that clause, the forms in that clause are evaluated
as an implicit progn, and the values it returns are returned as the value
of the case, ccase, or ecase form."
There is a hyperlink on "same." When I go there, it basically just says that
things are the same if a predicate says they are, but it leave it open as
to what that predicate is.
From a simple test at the REPL, it looks like CASE can't deal with strings
well:
CL-USER> (case "foo"
("abc" 1)
("foo" 2))
NIL
So that makes me think it's using either EQ or EQL as its predicate.
Is that just a default that I can change, or is it hardwired that way. I
can't seem to find any keyword parameter to override it.
--
Dave Roberts, ·············@re-move.droberts.com
Slowly but surely, the programming world is finding Lisp...
http://www.findinglisp.com/blog
In article <···················@attbi_s54>,
Dave Roberts <·············@re-move.droberts.com> wrote:
> Was reading the Hyperspec for CASE and was a bit stymied as to what
> conditional test it uses to make its comparisons. Specifically, the spec
> just says:
>
> "Each of the normal-clauses is then considered in turn. If the test-key is
> the same as any key for that clause, the forms in that clause are evaluated
> as an implicit progn, and the values it returns are returned as the value
> of the case, ccase, or ecase form."
>
> There is a hyperlink on "same." When I go there, it basically just says that
> things are the same if a predicate says they are, but it leave it open as
> to what that predicate is.
Look at definition #2 in the glossary entry. It says that if no
predicate is specified, EQL is used. Since the description of CASE
doesn't mention a particular predicate, this is the definition that
matters.
--
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
Barry Margolin wrote:
> In article <···················@attbi_s54>,
> Dave Roberts <·············@re-move.droberts.com> wrote:
>
>> Was reading the Hyperspec for CASE and was a bit stymied as to what
>> conditional test it uses to make its comparisons. Specifically, the spec
>> just says:
>>
>> "Each of the normal-clauses is then considered in turn. If the test-key
>> is the same as any key for that clause, the forms in that clause are
>> evaluated as an implicit progn, and the values it returns are returned as
>> the value of the case, ccase, or ecase form."
>>
>> There is a hyperlink on "same." When I go there, it basically just says
>> that things are the same if a predicate says they are, but it leave it
>> open as to what that predicate is.
>
> Look at definition #2 in the glossary entry. It says that if no
> predicate is specified, EQL is used. Since the description of CASE
> doesn't mention a particular predicate, this is the definition that
> matters.
Thanks. I had missed the subtlety there. I'm finding that I really have to
read every word of things in the spec. It's a VERY exact document, even for
a spec. Lots of things turn on the second definition of a glossary entry,
for instance. ;-)
It happens that I figured it out concurrently, too. I just noticed that CASE
is a macro, not a special form, and expanded it.
Is there any way to change it or is it hardcoded?
If not, I guess the alternative is COND, right? (Which is what it basically
expands to--COND with EQL tests.)
--
Dave Roberts, ·············@re-move.droberts.com
Slowly but surely, the programming world is finding Lisp...
http://www.findinglisp.com/blog
In article <···················@attbi_s03>,
Dave Roberts <·············@re-move.droberts.com> wrote:
> Is there any way to change it or is it hardcoded?
No way.
> If not, I guess the alternative is COND, right? (Which is what it basically
> expands to--COND with EQL tests.)
Right. Some versions may optimize if they notice that all the cases are
integers within a small range -- an array of functions can then be used.
But in general it's just an abbreviation for a COND.
You could easily write your own STRING-EQUAL-CASE macro. Just take a
look at the source of CASE (if your CL implementation doesn't include
source, you can use the CMUCL source) and change EQL to STRING-EQUAL.
--
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
Dave Roberts asked:
> Is there any way to change it or is it hardcoded?
Yes and yes. You are not allowed to meddle with CASE, that
is COMMON-LISP:CASE to give the symbol its full name, but
you can always arrange for it to be shadowed by
DAVE-ROBERTS:CASE.
The useful thing to do is define your own macro, for example
(defmacro pcase (chooser-form predicate &body cases)
(let ((chooser-value (gensym)))
`(let ((,chooser-value ,chooser-form))
(cond ,@(mapcar
(lambda(case)
`((,predicate ,chooser-value (quote ,(car case)))
,@(cdr case)))
cases)))))
(macroexpand-1 '(pcase (+ 2 2) = (0 "zero")(1 "one")))
=> (LET ((#:G847 (+ 2 2)))
(COND ((= #:G847 '0) "zero") ((= #:G847 '1) "one")))
T
Then the annoying way that eql checks number types
(case 0 (0.0 'zero)
(1.0 'one)) => NIL
is avoided with
(pcase 0 = (0.0 'zero)
(1.0 'one)) => ZERO
and the choice of whether to attend to the cases of
characters becomes available
(pcase "one" string= ("one" 1)) => 1
(pcase "One" string= ("one" 1)) => NIL
(pcase "One" string-equal ("one" 1)) => 1
Better still, rather than write a more general version of
the built-in case, write a macro that captures knowledge
about your application. For example, if you know that you
nearly always want case independence, then write a case-of
macro that always uses string-equal. The odd special
occasion when you want case to be significant then stands
out in your code because it goes (cond ((string= x "foo")...
Alan Crowe
Edinburgh
Scotland
Alan Crowe <····@cawtech.freeserve.co.uk> writes:
> Dave Roberts asked:
> > Is there any way to change it or is it hardcoded?
> You are not allowed to meddle with CASE, that is COMMON-LISP:CASE [...]
> The useful thing to do is define your own macro, for example
>
> (defmacro pcase (chooser-form predicate &body cases)
But then you may want epcase and cpcase too (or pecase and pccase).
A more orthogonal approach could be to define a macro which transforms
the case form inside it, and use it like:
(with-case-predicate string-equal
(ccase name
("homer" "d'oh")
("farnsworth" "good news, everyone")))
--
Lars Brinkhoff, Services for Unix, Linux, GCC, HTTP
Brinkhoff Consulting http://www.brinkhoff.se/
Alan Crowe wrote:
> Yes and yes. You are not allowed to meddle with CASE, that
> is COMMON-LISP:CASE to give the symbol its full name, but
> you can always arrange for it to be shadowed by
> DAVE-ROBERTS:CASE.
Right, excellent.
--
Dave Roberts, ·············@re-move.droberts.com
Slowly but surely, the programming world is finding Lisp...
http://www.findinglisp.com/blog
Dave Roberts <·············@re-move.droberts.com> wrote in message news:<···················@attbi_s54>...
> Was reading the Hyperspec for CASE and was a bit stymied as to what
> conditional test it uses to make its comparisons.
EQL (whenever the predicate is not specified, it is EQL)
> Is that just a default that I can change, or is it hardwired that way. I
> can't seem to find any keyword parameter to override it.
You cannot override it.
CLISP offers an FCASE macro where you can specify the test:
<http://clisp.cons.org/impnotes/flow-dict.html#fcase>
(it expands into COND, but is compiled similar to CASE,
i.e., a HASH-TABLE-based GOTO).