From: Lowell Kirsh
Subject: why does this ecase form not work?
Date: 
Message-ID: <bkaq0j$bf8$1@mughi.cs.ubc.ca>
(ecase "a"
   ("a" 4)
   ("b" 5))

should give: 4

error (using clisp):
*** - The value of "a" must be one of "a", "b"
The value is: "a"



Lowell

From: Lowell Kirsh
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <bkaqn2$bk2$1@mughi.cs.ubc.ca>
I just realized from the macroexpansion, that the reason it's not 
working is because eql is being used but what i need is equal. Is there 
any way to have a case statement that uses equal?

Lowell
From: Paul F. Dietz
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <49ucnX--cPxRb_WiXTWJhA@dls.net>
Lowell Kirsh wrote:

>  Is there any way to have a case statement that uses equal?

Roll your own macro.

	Paul
From: Kenny Tilton
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <3F68F2CE.4060101@nyc.rr.com>
Lowell Kirsh wrote:
> I just realized from the macroexpansion, that the reason it's not 
> working is because eql is being used but what i need is equal. Is there 
> any way to have a case statement that uses equal?

Kinda:

(cdr (assoc "a" '(("a" . 4)("b" . 5)) :test 'string-equal))

Or write a macro

(defmacro case$ (keyform &rest clauses)
   (let ((key$ (gensym)))
       `(let ((,key$ ,keyform))
            (cond
              ,@(mapcar (lambda (clause)
                           (destructuring-bind (match$ &body code) clause
                              `((string-equal ,key$ ,match$) ,@code))))))

I just made that up, no idea if it is any good, certainly untested, and 
you need to deal with t or OTHERWISE, and if you want to support a list 
of matches...but that's the idea.

-- 

  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"I'm non-violent, but if a hawk comes down when I'm feeding
  my birds, I lose my temper and get my air rifle."
            --  Tenzin Gyatso, the Fourteenth Dalai Lama
From: Johannes Groedem
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <lzu17alqhd.fsf@unity.copyleft.no>
* Lowell Kirsh <······@cs.ubc.ca>:

> I just realized from the macroexpansion, that the reason it's not
> working is because eql is being used but what i need is equal. Is
> there any way to have a case statement that uses equal?

I like this one, courtesy of Erik Naggum:

http://groups.google.com/groups?safe=images&ie=UTF-8&oe=UTF-8&as_umsgid=3208606982556119%40naggum.net&lr=&hl=en

(Short link: http://cl.no/d9 )

-- 
Johannes Groedem <OpenPGP: 5055654C>
From: Edi Weitz
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <878yom349o.fsf@bird.agharta.de>
On Thu, 18 Sep 2003 05:34:06 +0200, Johannes Groedem <······@ifi.uio.no> wrote:

> (Short link: http://cl.no/d9 )

Never heard about that one. Is that done in Common Lisp? The URL seems
to insinuate that... :)

Edi.
From: Johannes Groedem
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <lz65jql99e.fsf@unity.copyleft.no>
* Edi Weitz <···@agharta.de>:

>> (Short link: http://cl.no/d9 )
> Never heard about that one. Is that done in Common Lisp? The URL
> seems to insinuate that... :)

Yes, it's Common Lisp, but the "cl" here stands for "Copyleft", not
"Common Lisp".  Feel free to pretend it stands for "Common Lisp",
though.

-- 
Johannes Groedem <OpenPGP: 5055654C>
From: Edi Weitz
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <8765jq1l24.fsf@bird.agharta.de>
On Thu, 18 Sep 2003 11:46:05 +0200, Johannes Groedem <······@ifi.uio.no> wrote:

> Yes, it's Common Lisp, but the "cl" here stands for "Copyleft", not
> "Common Lisp".  Feel free to pretend it stands for "Common Lisp",
> though.

:)

Did you publish the code somewhere? Or would you at least consider
advertising that it's Common Lisp?

You know, we need success stories... :)

Edi.
From: Johannes Groedem
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <lz1xuel8k0.fsf@unity.copyleft.no>
* Edi Weitz <···@agharta.de>:

> Did you publish the code somewhere? Or would you at least consider
> advertising that it's Common Lisp?

Yeah, you can get it at http://kopkillah.com/software/.  It's not
something I'm terribly proud of, though.  (Although it works just
fine.)

> You know, we need success stories... :)

It doesn't have many users.  Mostly people I know, so it's hardly
something that can be called a success story.  Besides, it's just a
rip-off of tinylink/makeashorterlink/etc anyway.  Nothing new.

Feel free to use it, though.

-- 
Johannes Groedem <OpenPGP: 5055654C>
From: Alan S. Crowe
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <86u177hy00.fsf@cawtech.freeserve.co.uk>
Do you have to solve this problem?

In Chapter 8 of ANSI Common Lisp, Paul Graham writes

   If you're going to write programs that operate on words,
   it's often a good idea to use symbols instead of strings,
   because symbols are conceptually atomic. Symbols can be
   compared in one step with eql, while strings have to be
   compared character-by-character with string-equal or
   string=

So one writes 

(ecase (intern "a")
(|a| 4)
(|b| 5))
4

which leverages the way that the vertical bars let you use
any string for a symbol name, and intern will run a
symbol table for you.

Alan Crowe
Edinburgh
Scotland
From: Paul F. Dietz
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <3F68F063.9070704@dls.net>
Lowell Kirsh wrote:
> (ecase "a"
>   ("a" 4)
>   ("b" 5))
> 
> should give: 4
> 
> error (using clisp):
> *** - The value of "a" must be one of "a", "b"
> The value is: "a"

Because ECASE compares using EQL, not STRING=, STRING-EQUAL, or EQUALP.
The two "a" strings are not guaranteed to be identical objects (which
they would have to be for EQL to succeed.)

Try this:

(eval (let ((x "a")) `(ecase ,x (,x 4) ("b" 5))))

	Paul
From: Edi Weitz
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <87r82f2co5.fsf@bird.agharta.de>
On Wed, 17 Sep 2003 16:16:35 -0700, Lowell Kirsh <······@cs.ubc.ca> wrote:

> (ecase "a"
>    ("a" 4)
>    ("b" 5))
> 
> should give: 4
> 
> error (using clisp):
> *** - The value of "a" must be one of "a", "b"
> The value is: "a"

You can't use CASE/CCASE/ECASE with strings. These forms try to match
the test-key based on its identity, i.e. (quoted from the HyperSpec)
"if the test-key is the same as any key for that clause, the forms in
that clause are evaluated."  Look up the CLHS glossary entry for
"same" and you'll see that the keys are compared with EQL.

You can relatively easy define your own CASE-like construct which,
say, uses EQUAL instead. Something like that, maybe[*]:

  (defmacro mycase (key-form &rest clauses)
    (let ((test-key (gensym)))
      `(let ((,test-key ,key-form))
        (cond
          ,@(loop for (keys . forms) in clauses
                  collect (cond ((or (eq keys t)
                                     (eq keys 'otherwise))
                                  `(t ,@forms))
                                ((listp keys)
                                  `((or ,@(mapcar (lambda (key)
                                                    `(equal ,test-key ,key))
                                                  keys))
                                    ,@forms))
                                (t
                                  `((equal ,test-key ,keys)
                                    ,@forms))))))))

  (defun foo (x)
    (mycase x
      (("bar" "baz")
       (print 23) 44)
      ("foo"
       42)
      (otherwise
       'not-found)))

Which yields:

  * (foo "bar")
  23 
  44
  * (foo "foo")
  42
  * (foo "frob")
  NOT-FOUND

The fact that CASE "only" uses EQL allows your CL implementation to
create optimized code (think of it as a kind of "computed GOTO" at
compile time). This wouldn't be the same with EQUAL or EQUALP.

Edi.


[*] This is not meant to be as a reference implementation but just to
    illustrate my point. I haven't thought about this code for more
    than two minutes and I haven't tested it expect for the FOO
    function above. (I'm pretty sure someone will find a flaw and
    nitpick so I better say this in advance.)
From: Thomas F. Burdick
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <xcvd6dyamjq.fsf@famine.OCF.Berkeley.EDU>
Edi Weitz <···@agharta.de> writes:

> You can relatively easy define your own CASE-like construct which,
> say, uses EQUAL instead. Something like that, maybe[*]:

Although, if you're going to be making your own CASE-like macros, you
might as well factor the test out:

  (defmacro case-if ((key-form &optional test) &rest clauses)
    "Like CASE, but you can supply an arbitrary test function."
>     (let ((test-key (gensym))
            (test-fun (gensym)))
>       `(let ((,test-key ,key-form)
               (,test-fun ,(or test 'eql)))
>         (cond
>           ,@(loop for (keys . forms) in clauses
>                   collect (cond ((or (eq keys t)
>                                      (eq keys 'otherwise))
>                                   `(t ,@forms))
>                                 ((listp keys)
>                                   `((or ,@(mapcar (lambda (key)
                                                      `(,test-fun ,test-key ,key))
>                                                   keys))
>                                     ,@forms))
>                                 (t
                                    `((,test-fun ,test-key ,keys)
>                                     ,@forms))))))))

> The fact that CASE "only" uses EQL allows your CL implementation to
> create optimized code (think of it as a kind of "computed GOTO" at
> compile time). This wouldn't be the same with EQUAL or EQUALP.

In my experience, this has been a theoretical advantage.  Do any
implementations make this optimization?

> [*] This is not meant to be as a reference implementation but just to
>     illustrate my point. I haven't thought about this code for more
>     than two minutes and I haven't tested it expect for the FOO
>     function above. (I'm pretty sure someone will find a flaw and
>     nitpick so I better say this in advance.)

Just to clarify, I'm not nitpicking, I'm expanding on your post (ie,
collaborative help).  :)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Duane Rettig
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <4llsmzmqi.fsf@beta.franz.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Edi Weitz <···@agharta.de> writes:

> > The fact that CASE "only" uses EQL allows your CL implementation to
> > create optimized code (think of it as a kind of "computed GOTO" at
> > compile time). This wouldn't be the same with EQUAL or EQUALP.
> 
> In my experience, this has been a theoretical advantage.  Do any
> implementations make this optimization?

Absolutely.  Although the cutoff point for it being an advantage
differs from architecture to architecture.  On some architectures,
like the x86, a call is needed to get the current program counter.
On other architectures, like HP's PA-RISC and AMDs x86-64, there are
built-in pc-relative branches and loads explicitly for this purpose.
On the rs/6000 (and PowerPC arctitectures), which have multiple
condition registers, we perform tests in triplets, and then conditional
branches in triplets; because the tests have had time to settle in the
pipeline, the three branch/no-branch decisions each take zero time.

The tradeoff on the jump-table technique depends on how many cycles it
takes to calculate the jump address, as opposed to an average of how
the instructions it takes to run through cond-style or if/then/elseif/...
tests in the assembled code.  If the cond-style is selected, the first
test is fastest, of course, and the last is slowest, and whether or not
the case statement is more or less than average depends on which cases
are actually selected.  If the jump table is selected, then the first
test or two loses somewhat because of the setup overhead, but because
every test takes constant time, larger jump tables and case statements
which have balanced distribution win big.

Some typecase statements also are prime candidates for this
optimization, because they can turn into a case statement with
a 1-of-256 numeric table.

Here is an example of a case statement on an x86, for which the
maximum table size is 256 (i.e. that is the maximum distance
between the numeric cases in order to use the jump table) and the
minimum count of numeric cases to switch from cond to jump-table
is 4:

CL-USER(1): (defun foo (x)
              (declare (optimize speed (safety 0)))
              (case x
                ((1 3 5 6) 'hi)
                ((2 4 7) 'bye)
                (t 'oops)))
FOO
CL-USER(2): (compile 'foo)
FOO
NIL
NIL
CL-USER(3): (disassemble 'foo)
;; disassembly of #<Function FOO>
;; formals: X
;; constant vector:
0: OOPS
1: HI
2: BYE

;; code start: #x714b66f4:
   0: 55          pushl	ebp
   1: 8b ec       movl	ebp,esp
   3: 56          pushl	esi
   4: 83 ec 24    subl	esp,$36
   7: 8b c8       movl	ecx,eax
   9: c1 c9 02    rorl	ecx,$2
  12: 83 f9 07    cmpl	ecx,$7
  15: 77 32       jnbe	67
  17: e8 00 00 00 call	22
      00 
  22: 5b          popl	ebx
  23: 8b 4c 8b 09 movl	ecx,[ebx+ecx*4+9])
  27: 03 cb       addl	ecx,ebx
  29: ff e1       jmp	*ecx
  31: 2d 00 00 00 .long	$45
  35: 36 00 00 00 .long	$54
  39: 3c 00 00 00 .long	$60
  43: 36 00 00 00 .long	$54
  47: 3c 00 00 00 .long	$60
  51: 36 00 00 00 .long	$54
  55: 36 00 00 00 .long	$54
  59: 3c 00 00 00 .long	$60
  63: 00 00 00 00 .long	$0
  67: 8b 46 12    movl	eax,[esi+18]    ; OOPS
  70: f8          clc
  71: c9          leave
  72: 8b 75 fc    movl	esi,[ebp-4]
  75: c3          ret
  76: 8b 46 16    movl	eax,[esi+22]    ; HI
  79: f8          clc
  80: eb f5       jmp	71
  82: 8b 46 1a    movl	eax,[esi+26]    ; BYE
  85: f8          clc
  86: eb ef       jmp	71
CL-USER(4): 


-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Thomas F. Burdick
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <xcvy8wmypis.fsf@famine.OCF.Berkeley.EDU>
Duane Rettig <·····@franz.com> writes:

> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > Edi Weitz <···@agharta.de> writes:
> 
> > > The fact that CASE "only" uses EQL allows your CL implementation to
> > > create optimized code (think of it as a kind of "computed GOTO" at
> > > compile time). This wouldn't be the same with EQUAL or EQUALP.
> > 
> > In my experience, this has been a theoretical advantage.  Do any
> > implementations make this optimization?
> 
> Absolutely.  Although the cutoff point for it being an advantage
> differs from architecture to architecture.

Oh, good.  I've only worked with Allegro a little bit, so I never
investigated further to see if it is able to compile CASE into a jump
table.  Thanks for the informative post...

> ;; code start: #x714b66f4:

Wow, I'm getting really spoiled in my little SPARC and PPC world.  x86
code is ug-ly.  I can still read it, though :-)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Edi Weitz
Subject: Re: why does this ecase form not work?
Date: 
Message-ID: <87d6dy34ce.fsf@bird.agharta.de>
On 17 Sep 2003 18:54:33 -0700, ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:

> Edi Weitz <···@agharta.de> writes:
> 
> > [*] This is not meant to be as a reference implementation but just to
> >     illustrate my point. I haven't thought about this code for more
> >     than two minutes and I haven't tested it expect for the FOO
> >     function above. (I'm pretty sure someone will find a flaw and
> >     nitpick so I better say this in advance.)
> 
> Just to clarify, I'm not nitpicking, I'm expanding on your post (ie,
> collaborative help).  :)

Yeah, that's fine with me... :)

Edi.