From: Dave Roberts
Subject: What predicate does CASE use?
Date: 
Message-ID: <MaRxc.63574$3x.9976@attbi_s54>
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

From: Barry Margolin
Subject: Re: What predicate does CASE use?
Date: 
Message-ID: <barmar-006EEB.00135810062004@comcast.dca.giganews.com>
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 ***
From: Dave Roberts
Subject: Re: What predicate does CASE use?
Date: 
Message-ID: <QnRxc.10202$0y.8409@attbi_s03>
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
From: Barry Margolin
Subject: Re: What predicate does CASE use?
Date: 
Message-ID: <barmar-5FE192.01411910062004@comcast.dca.giganews.com>
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 ***
From: Alan Crowe
Subject: Re: What predicate does CASE use?
Date: 
Message-ID: <86u0xjgybo.fsf@cawtech.freeserve.co.uk>
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
From: Lars Brinkhoff
Subject: Re: What predicate does CASE use?
Date: 
Message-ID: <85ekonl3zc.fsf@junk.nocrew.org>
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/
From: Dave Roberts
Subject: Re: What predicate does CASE use?
Date: 
Message-ID: <oIayc.7876$2i5.3667@attbi_s52>
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
From: Sam Steingold
Subject: Re: What predicate does CASE use?
Date: 
Message-ID: <ed53d366.0406101123.18212a05@posting.google.com>
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).