From: J.C. Roberts
Subject: Using (CASE ...) with strings?
Date: 
Message-ID: <lq6rm190tj94lpfr71e4ogfh9o5f25im1h@4ax.com>
#|

It seems I'm misunderstanding HyperSpec when it comes to the 
(CASE ...) macro.

http://www.lisp.org/HyperSpec/Body/mac_casecm_ccasecm_ecase.html#case

I _think_ it is supposed to evaluate the keyform and then compare the
result to the keys of the successive normal-clauses until it finds a 
match (i.e with "the same" as defined by 
http://www.lisp.org/HyperSpec/Body/glo_s.html#same)

(CASE ...) works fine when used with numbers or symbols but what I 
don't understand is why it fails miserably on strings?

  (case "mystring" 
    ("fakestr1" (print "Dummy1: Nope, wrong string."))
    ("mystring" (print "Dummy1: Happy Days Are Here Again!"))
    ("fakestr1" (print "Dummy1: Nope, wrong string again."))
    (t          (print "Dummy1: Nope, I still don't get it.")))
  ;>> "Dummy1: Nope, I still don't get it."

  (case "mystring"
    (fakestr1 (print "Dummy2: Nope, wrong string."))
    (mystring (print "Dummy2: Happy Days Are Here Again!"))
    (fakestr1 (print "Dummy2: Nope, wrong string again."))
    (t        (print "Dummy2: Nope, I still don't get it.")))
  ;>> "Dummy2: Nope, I still don't get it."


Since the second does not generate errors, it's obvious that the keys
are not evaluated, they just are treated as symbols.

I've tried all sorts of similar tests in the source code below but I
come up empty handed each time.

Since I've failed to get this right with three different Common LISP
implementations, I know the fault is my own.

Am I failing to correctly create proper "keys" ?
Is the keyform not being evaluated as I expect?
Have I failed to understand what it means to be the "same" in CL?

Just translating the string to a symbol is not going to work since some
of the data (from external programs) will contain spaces. In essence I 
need logical branching on strings.

Something like this:

(setq lyric "Oaklahoma where the wind comes sweeping down the lane")
(case lyric
  ("Each evening from December to December"
    (print "Camelot")
    (play "camelot.mp3))
  ("Good night my someone, goodnight my love"
    (print "Music Man")
    (play "music_man.mp3"))
  ("Hear me now oh thy cuel and unbearable world" 
    (print "Don Quixote")
    (play "don_quixote.mp3))
  (t (print "I'm sorry Dave, I can't do that.")))


If you spend the rest of your day with a show tune stuck in your head, 
try to not hold it against me. ;-)

Is the CL answer to use a set of (COND ..) or (WHEN ...) statements 
and if so, is the pseudo-block optimized by the compiler to reduce 
regex overhead?


|#

(defun case-test ()

  (case "mystring" 
    ("fakestr1" (print "Dummy1: Nope, wrong string."))
    ("mystring" (print "Dummy1: Happy Days Are Here Again!"))
    ("fakestr1" (print "Dummy1: Nope, wrong string again."))
    (t          (print "Dummy1: Nope, I still don't get it.")))
  ;>> "Dummy1: Nope, I still don't get it."

  (case "mystring"
    (fakestr1 (print "Dummy2: Nope, wrong string."))
    (mystring (print "Dummy2: Happy Days Are Here Again!"))
    (fakestr1 (print "Dummy2: Nope, wrong string again."))
    (t        (print "Dummy2: Nope, I still don't get it.")))
  ;>> "Dummy2: Nope, I still don't get it."
  

  ;--------------------------------------------------
  ; case-test nil
  (format t "~%~%~A" "case-test nil")
  (setq var nil)
  (case var
    (nil    (format t "~%~A" "Got nil"))
    ((nil)  (format t "~%~A" "Got (nil)"))
    ((t)    (format t "~%~A" "Got (t)"))
    (t      (format t "~%~A" "Got t")))
  ;>> case-test nil
  ;>> Got (nil)
  ; somewhat unexpected result -Why must nil be inside parens?

  ;--------------------------------------------------
  ; case-test t
  (format t "~%~%~A" "case-test t")
  (setq var t)
  (case var
    (nil    (format t "~%~A" "Got nil"))
    ((nil)  (format t "~%~A" "Got (nil)"))
    ((t)    (format t "~%~A" "Got (t)"))
    (t      (format t "~%~A" "Got t")))
  ;>> case-test t
  ;>> Got (t)
  ; unexpected result -Why must t be inside parens?

  ;--------------------------------------------------
  ; case-test numeric
  (format t "~%~%~A" "case-test numeric")
  (setq var 2)
  (case var
    (1      (format t "~%~A" "Got 1"))
    (2      (format t "~%~A" "Got 2"))
    (3      (format t "~%~A" "Got 3"))
    (nil    (format t "~%~A" "Got nil"))
    ((nil)  (format t "~%~A" "Got (nil)"))
    ((t)    (format t "~%~A" "Got (t)"))
    (t      (format t "~%~A" "Got t")))
  ;>> case-test numeric
  ;>> Got 2
  ; the result here makes sense

  ;--------------------------------------------------
  ; case-test symbolic
  (format t "~%~%~A" "case-test symbolic")
  (setq var 'bbb)
  (case var
    ('aaa   (format t "~%~A" "Got aaa symbol"))
    ('bbb   (format t "~%~A" "Got bbb symbol"))
    ('ccc   (format t "~%~A" "Got ccc symbol"))
    (nil    (format t "~%~A" "Got nil"))
    ((nil)  (format t "~%~A" "Got (nil)"))
    ((t)    (format t "~%~A" "Got (t)"))
    (t      (format t "~%~A" "Got t")))
  ;>> case-test symbolic
  ;>> Got bbb symbol
  ; the result here makes sense
    

  ;--------------------------------------------------
  ; case-test string-1
  (format t "~%~%~A" "case-test string-1")
  (setq var "yyy")
  (case var
    ("xxx"  (format t "~%~A" "Got xxx string"))
    ("yyy"  (format t "~%~A" "Got yyy string"))
    ("zzz"  (format t "~%~A" "Got zzz string"))
    (nil    (format t "~%~A" "Got nil"))
    ((nil)  (format t "~%~A" "Got (nil)"))
    ((t)    (format t "~%~A" "Got (t)"))
    (t      (format t "~%~A" "Got t")))
  ;>> case-test string-1
  ;>> Got t
  ; unextected result -Why is the string not compared?

  ;--------------------------------------------------
  ; case-test string-2
  (format t "~%~%~A" "case-test string-2")
  (setq var "yyy")
  (case var
    (("xxx") (format t "~%~A" "Got xxx string"))
    (("yyy") (format t "~%~A" "Got yyy string"))
    (("zzz") (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-2
  ;>> Got t
  ; unextected result -Why is the string *still* not compared?


  ;--------------------------------------------------
  ; case-test string-3
  (format t "~%~%~A" "case-test string-3")
  (setq var (list "yyy"))
  (case var
    (("xxx") (format t "~%~A" "Got xxx string"))
    (("yyy") (format t "~%~A" "Got yyy string"))
    (("zzz") (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-3
  ;>> Got t
  ; unextected result -Why is the string *still* not compared?


  ;--------------------------------------------------
  ; case-test string-4
  (format t "~%~%~A" "case-test string-4")
  (setq var "yyy")
  (case var
    (xxx (format t "~%~A" "Got xxx string"))
    (yyy (format t "~%~A" "Got yyy string"))
    (zzz (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-4
  ;>> Got t
  ; unextected result -Why is the string *still* not compared?
  ; I thought this would generate an error but it does not?


  ;--------------------------------------------------
  ; case-test string-5
  (format t "~%~%~A" "case-test string-5")
  (setq var "yyy")
  (case var
    ('xxx (format t "~%~A" "Got xxx string"))
    ('yyy (format t "~%~A" "Got yyy string"))
    ('zzz (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-5
  ;>> Got t
  ; unextected result -Why is the string *still* not compared?
  ; I thought this would generate an error of some sort but it does not?


  ;--------------------------------------------------
  ; case-test string-6
  (format t "~%~%~A" "case-test string-6")
  (setq var "yyy")
  (setq an1 "xxx")
  (setq an2 "yyy")
  (setq an3 "zzz")
  (case var
    (an1 (format t "~%~A" "Got xxx string"))
    (an2 (format t "~%~A" "Got yyy string"))
    (an3 (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-6
  ;>> Got t


  ;--------------------------------------------------
  ; case-test string-7
  (format t "~%~%~A" "case-test string-7")
  (setq var "yyy")
  (setq an1 "xxx")
  (setq an2 "yyy")
  (setq an3 "zzz")
  (case var
    ((an1) (format t "~%~A" "Got xxx string"))
    ((an2) (format t "~%~A" "Got yyy string"))
    ((an3) (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-7
  ;>> Got t


  ;--------------------------------------------------
  ; case-test string-8
  (format t "~%~%~A" "case-test string-8")
  (setq var "yyy")
  (case (format nil "~A" var)
    (xxx (format t "~%~A" "Got xxx string"))
    (yyy (format t "~%~A" "Got yyy string"))
    (zzz (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-8
  ;>> Got t



  ;--------------------------------------------------
  ; case-test string-9
  (format t "~%~%~A" "case-test string-9")
  (setq var "yyy")
  (case (format nil "~S" var)
    ("xxx" (format t "~%~A" "Got xxx string"))
    ("yyy" (format t "~%~A" "Got yyy string"))
    ("zzz" (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-9
  ;>> Got t
 


  ;--------------------------------------------------
  ; /me/ running out of bad ideas to try...
  ; case-test string-10
  (format t "~%~%~A" "case-test string-10")
  (case "yyy"
    ("xxx" (format t "~%~A" "Got xxx string"))
    ("yyy" (format t "~%~A" "Got yyy string"))
    ("zzz" (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-10
  ;>> Got t



  ;--------------------------------------------------
  ; /me/ running out of bad ideas to try...
  ; case-test string-11
  (format t "~%~%~A" "case-test string-11")
  (case "yyy"
    (xxx (format t "~%~A" "Got xxx string"))
    (yyy (format t "~%~A" "Got yyy string"))
    (zzz (format t "~%~A" "Got zzz string"))
    (nil     (format t "~%~A" "Got nil"))
    ((nil)   (format t "~%~A" "Got (nil)"))
    ((t)     (format t "~%~A" "Got (t)"))
    (t       (format t "~%~A" "Got t")))
  ;>> case-test string-11
  ;>> Got t

);end defun
(case-test)

From: Julian Squires
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <kMWdncTfPdIEZfDenZ2dnUVZ_smdnZ2d@rogers.com>
On 2005-11-06, J.C  Roberts <···············@abac.com> wrote:
> (CASE ...) works fine when used with numbers or symbols but what I 
> don't understand is why it fails miserably on strings?

Check out Erik Naggum's excellent article on working around this with
messageid <················@naggum.net>.  (and the rest of that thread)

Cheers.

-- 
Julian Squires
From: J.C. Roberts
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <5purm1pm2fmv2v33secs2bh098bme2u83t@4ax.com>
On Sun, 06 Nov 2005 06:35:37 -0600, Julian Squires <······@cipht.net>
wrote:

>On 2005-11-06, J.C  Roberts <···············@abac.com> wrote:
>> (CASE ...) works fine when used with numbers or symbols but what I 
>> don't understand is why it fails miserably on strings?
>
>Check out Erik Naggum's excellent article on working around this with
>messageid <················@naggum.net>.  (and the rest of that thread)
>
>Cheers.
>
>-- 
>Julian Squires

Thanks Julian,

Previously trying to use deja-google to search this group for the terms
"case string compare" was an exercise in futility. ;-)

JCR
From: Frank Buss
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <7oeswuynvyfy.w9nd2zgoiiye$.dlg@40tude.net>
Julian Squires wrote:

> On 2005-11-06, J.C  Roberts <···············@abac.com> wrote:
>> (CASE ...) works fine when used with numbers or symbols but what I 
>> don't understand is why it fails miserably on strings?
> 
> Check out Erik Naggum's excellent article on working around this with
> messageid <················@naggum.net>.  (and the rest of that thread)

Perhaps it is a problem of Google groups, this is the link:

http://groups.google.com/group/comp.lang.lisp/msg/a79ba3b04895a4d8

but it doesn't work. There is a missing paranthese at the end and looks
like anything I write in the form in a with-hashed-identity form is simply
ignored (tested on LispWorks).

Another equal-case:

(defmacro equal-case (keyform &body clauses)
  `(cond ,@(loop for clause in clauses collect
                 (destructuring-bind (test exec) clause
                   (if (or (eql test t) (eql test 'otherwise))
                       `(t ,exec)
                     `((equal ,keyform ,test) ,exec))))))

(equal-case "test"
  ("hello" (+ 1 2))
  ((concatenate 'string "te" "st") 2)
  (t 3))

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Edi Weitz
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <u4q6pssi0.fsf@agharta.de>
On Sun, 6 Nov 2005 16:18:02 +0100, Frank Buss <··@frank-buss.de> wrote:

> Perhaps it is a problem of Google groups, this is the link:
>
> http://groups.google.com/group/comp.lang.lisp/msg/a79ba3b04895a4d8
>
> but it doesn't work. There is a missing paranthese at the end

Not at the end but after the ERROR form.

Cheers,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Kenny Tilton
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <nDjbf.13276$u43.11505@twister.nyc.rr.com>
J.C. Roberts wrote:
> #|
> 
> It seems I'm misunderstanding HyperSpec when it comes to the 
> (CASE ...) macro.
> 
> http://www.lisp.org/HyperSpec/Body/mac_casecm_ccasecm_ecase.html#case
> 
> I _think_ it is supposed to evaluate the keyform and then compare the
> result to the keys of the successive normal-clauses until it finds a 
> match (i.e with "the same" as defined by 
> http://www.lisp.org/HyperSpec/Body/glo_s.html#same)

But that says in the second definition:

"2. (of objects if no predicate is implied by context) indistinguishable 
by eql"

I would expect the compiler to re-use string literals from a table such 
that two "mystring" refs would be EQL, but apparently not in this case.

(eql "a" "a") -> NIL

> 
> (CASE ...) works fine when used with numbers or symbols but what I 
> don't understand is why it fails miserably on strings?

numbers and symbols are eql when they look the same in source (putting 
it badly but it is late here).


-- 
Kenny

Why Lisp? http://wiki.alu.org/RtL_Highlight_Film

"I've wrestled with reality for 35 years, Doctor, and I'm happy to state 
I finally won out over it."
     Elwood P. Dowd, "Harvey", 1950
From: Kalle Olavi Niemitalo
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <87k6fmqf2y.fsf@Astalo.kon.iki.fi>
Kenny Tilton <·······@nyc.rr.com> writes:

>> (CASE ...) works fine when used with numbers or symbols but what I
>> don't understand is why it fails miserably on strings?
>
> numbers and symbols are eql when they look the same in source (putting 
> it badly but it is late here).

GNU CLISP has an extension that lets one specify a test other
than the default EQL.

http://clisp.sourceforge.net/impnotes.html#fcase

If the interface of the EXT:FCASE macro is convenient, I suppose
it wouldn't be too hard define a similar macro in one's program.
From: Espen Vestre
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <m1vez5riqj.fsf@vestre.net>
Kenny Tilton <·······@nyc.rr.com> writes:

> But that says in the second definition:
> 
> "2. (of objects if no predicate is implied by context)
> indistinguishable by eql"

Everybody with an "equal-case" in their macro toolbox: Raise hands!

*raising hand*
-- 
  (espen)
From: Steven E. Harris
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <q94ll008f8b.fsf@chlorine.gnostech.com>
Espen Vestre <·····@vestre.net> writes:

> Raise hands!

I just wrote one last week.

Of course I noticed that the test function should be generalized, but
couldn't think of a good name for the generalized version. Kalle Olavi
Niemitalo pointed out CLISP's EXT:fcase, which is nice solution.


Looking at my own version again, I noticed that I wasn't looking to
change the EQL test, but rather the quoting of symbols used as
keys. An example will demonstrate the problem. I wanted to write
something like this:

(defconstant +FOO+ 1)
(defconstant +BAR+ 2)

(case (random 3)
  (+FOO+ "foo")
  (+BAR+ "bar")
  (t "other))


This form always returns "other", because in the case expansion the
keys are all quoted symbols. That is, (eql +FOO+ 1) is T, but (eql
'+FOO+ 1) is obviously nil, and case produces the latter.

Reading the Hyperspec, I don't see where it says that the keys will be
quoted, other than in the Notes section's equivalent
expansion. Perhaps this quoting/non-evaluating behavior for keys is
wrapped up in the phrase "designator for a list objects".

-- 
Steven E. Harris
From: Pascal Costanza
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <3t9nipFrmjgvU1@individual.net>
Steven E. Harris wrote:

> Looking at my own version again, I noticed that I wasn't looking to
> change the EQL test, but rather the quoting of symbols used as
> keys. An example will demonstrate the problem. I wanted to write
> something like this:
> 
> (defconstant +FOO+ 1)
> (defconstant +BAR+ 2)
> 
> (case (random 3)
>   (+FOO+ "foo")
>   (+BAR+ "bar")
>   (t "other))
> 
> This form always returns "other", because in the case expansion the
> keys are all quoted symbols. That is, (eql +FOO+ 1) is T, but (eql
> '+FOO+ 1) is obviously nil, and case produces the latter.

Try:

(case (random 3)
   (#.+foo+ "foo")
   (#.+bar+ "bar")
   (t "other"))


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: Steven E. Harris
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <q94acgg8d2a.fsf@chlorine.gnostech.com>
Pascal Costanza <··@p-cos.net> writes:

> (case (random 3)
>   (#.+foo+ "foo")
>   (#.+bar+ "bar")
>   (t "other"))

This works for constants known at read-time, which would have solved
my original problem.

Is there a similar solution that would address symbols denoting values
that could change at run-time, such as this example?

(defvar *baz* 3)

;; ...

(let ((foo 0)
      (bar (1+ (random 1))))
  (case (random 4)
    (foo "foo")
    (bar "bar")
    (*baz* "baz")
    (t "other")))

-- 
Steven E. Harris
From: Edi Weitz
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <umzkg5jox.fsf@agharta.de>
On Mon, 07 Nov 2005 11:37:01 -0800, "Steven E. Harris" <···@panix.com> wrote:

> Is there a similar solution that would address symbols denoting
> values that could change at run-time, such as this example?

Julian Squires has already answered your question in this thread.

Cheers,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Edi Weitz
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <uirv45jii.fsf@agharta.de>
On Mon, 07 Nov 2005 20:42:06 +0100, Edi Weitz <········@agharta.de> wrote:

> Julian Squires has already answered your question in this thread.

No, sorry, that was wrong.  But see Frank Buss' solution for example.

Cheers,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Steven E. Harris
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <q94slu86xng.fsf@chlorine.gnostech.com>
Edi Weitz <········@agharta.de> writes:

> But see Frank Buss' solution for example.

Yes, Frank's equal-case almost exactly the same as my hand-rolled
version that I wrote last week, using EQL instead of EQUAL. The only
difference between my version and the typical CASE is the
quoting/evaluation of the keys. That I had trouble coming up with a
name for such a beast (eval-case?) was a sign that my efforts were
misguided.

I was mainly asking, "Should I really have to write a macro like this,
or is there a different way to specify the keys to CASE?" Using the
#.key notation is a partial answer to my question.

-- 
Steven E. Harris
From: Edi Weitz
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <uoe4w43rw.fsf@agharta.de>
On Mon, 07 Nov 2005 11:55:15 -0800, "Steven E. Harris" <···@panix.com> wrote:

> I was mainly asking, "Should I really have to write a macro like
> this, or is there a different way to specify the keys to CASE?"
> Using the #.key notation is a partial answer to my question.

The answer is no, there is no other way.  They keys for a CASE
statement are supposed to be known at compile time so the compiler can
generate efficient code - basically like `switch' in C.  If you want
to have different behaviour you'll have to roll your own macro.

Cheers,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Pascal Costanza
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <3t9p1nFrqt3vU1@individual.net>
Steven E. Harris wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
> 
>>(case (random 3)
>>  (#.+foo+ "foo")
>>  (#.+bar+ "bar")
>>  (t "other"))
> 
> 
> This works for constants known at read-time, which would have solved
> my original problem.
> 
> Is there a similar solution that would address symbols denoting values
> that could change at run-time, such as this example?
> 
> (defvar *baz* 3)
> 
> ;; ...
> 
> (let ((foo 0)
>       (bar (1+ (random 1))))
>   (case (random 4)
>     (foo "foo")
>     (bar "bar")
>     (*baz* "baz")
>     (t "other")))

No, use COND for this, or write your own macro.


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: Steven E. Harris
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <q94zmog6xp0.fsf@chlorine.gnostech.com>
Pascal Costanza <··@p-cos.net> writes:

> No, use COND for this, or write your own macro.

Alas, I already did, but then thought maybe it's not necessary. Now I
just don't know what to call it.

-- 
Steven E. Harris
From: Pascal Costanza
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <3t9r5lFs0d16U1@individual.net>
Steven E. Harris wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
>>No, use COND for this, or write your own macro.> 
> Alas, I already did, but then thought maybe it's not necessary. Now I
> just don't know what to call it.

A different approach could be to use one of the existing versions and 
stick to those names. This avoids the NIH syndrome and helps at least 
some other people to better understand your code.


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: Steven E. Harris
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <q947jbk6r5c.fsf@chlorine.gnostech.com>
Pascal Costanza <··@p-cos.net> writes:

> A different approach could be to use one of the existing versions
> and stick to those names. This avoids the NIH syndrome and helps at
> least some other people to better understand your code.

Agreed. I happened to have written mine mostly as a learning exercise,
deliberately trying to not look at other solutions until I had gotten
mine to work properly.

Having said that, I again want to emphasize that the point of the
various other versions (perhaps Frank's aside) is to supplant the EQL
test with a different test, whereas my need was to keep EQL and
compare against evaluated/non-quoted keys.

-- 
Steven E. Harris
From: Thomas A. Russ
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <ymiu0eoqgqx.fsf@sevak.isi.edu>
J.C. Roberts <···············@abac.com> writes:

> 
> #|
> 
> It seems I'm misunderstanding HyperSpec when it comes to the 
> (CASE ...) macro.
> 
> http://www.lisp.org/HyperSpec/Body/mac_casecm_ccasecm_ecase.html#case
> 
> I _think_ it is supposed to evaluate the keyform and then compare the
> result to the keys of the successive normal-clauses until it finds a 
> match (i.e with "the same" as defined by 
> http://www.lisp.org/HyperSpec/Body/glo_s.html#same)
> 
> (CASE ...) works fine when used with numbers or symbols but what I 
> don't understand is why it fails miserably on strings?
> 
>   (case "mystring" 
>     ("fakestr1" (print "Dummy1: Nope, wrong string."))
>     ("mystring" (print "Dummy1: Happy Days Are Here Again!"))
>     ("fakestr1" (print "Dummy1: Nope, wrong string again."))
>     (t          (print "Dummy1: Nope, I still don't get it.")))
>   ;>> "Dummy1: Nope, I still don't get it."
> 
>   (case "mystring"
>     (fakestr1 (print "Dummy2: Nope, wrong string."))
>     (mystring (print "Dummy2: Happy Days Are Here Again!"))
>     (fakestr1 (print "Dummy2: Nope, wrong string again."))
>     (t        (print "Dummy2: Nope, I still don't get it.")))
>   ;>> "Dummy2: Nope, I still don't get it."
> 
> Since the second does not generate errors, it's obvious that the keys
> are not evaluated, they just are treated as symbols.
...
> Is the CL answer to use a set of (COND ..) or (WHEN ...) statements 
> and if so, is the pseudo-block optimized by the compiler to reduce 
> regex overhead?

Yes, the CL answer would be to use a set of tests.  That is because of
the type of test specified for the CASE statement.  It is based on EQL,
and two strings consisting of the same characters are not required to be
EQL, only EQUAL.

So, there are actually a couple of CL-style solutions to your problem.
I'll sketch out three of them.

(1)  Use symbols instead of strings.  This will work even with long
strings, since symbol names can contain any character.  You would then
need to just use symbols as keys, with appropriate escapes to preserve
the case:

  (case 'mystring
    (|fakestr1| (print "Dummy2: Nope, wrong string."))
    (|mystring| (print "Dummy2: Happy Days Are Here Again!"))
    (|fakestr1| (print "Dummy2: Nope, wrong string again."))
    (t          (print "Dummy2: Nope, I still don't get it.")))

If you want to take the input as a string you can get the same effect
by interning it if necessary, although that will give up some of the
runtime advantages of using symbols:

  (case (intern "mystring" *my-package*)
    (fakestr1 (print "Dummy2: Nope, wrong string."))
    (mystring (print "Dummy2: Happy Days Are Here Again!"))
    (fakestr1 (print "Dummy2: Nope, wrong string again."))
    (t        (print "Dummy2: Nope, I still don't get it.")))

You do need to take care to intern the strings into the proper package,
or else the comparison won't work.

(2)  Write a series of COND tests:

 (let ((test-string "mystring"))
    (cond ((string-eql test-string "fakestring")
            ...)
          ((string-eql test-string "mystring")
           ...)))

This is straightforward, but doesn't necessarily show the structure of
the dispatch you are doing quite as clearly as CASE would.  But you can
solve that with the third suggestion:

(3) Is a variant on item 2, which is to write a macro that constructs
the COND chain you want to have.  You do need to decide whether you want
the comparison to be based on a case-sensitive (STRING-EQL) or
case-insensitive (STRING-EQUAL) test, or else you could make the macro
more complicated by providing a way to specify the test.  Since I can't
think of any non-awkward way to do that, I'll pick a simple
implementation.

(defmacro string-case (item &rest clauses)
  (let ((test-var (gensym)))    ; Used to insure only one evaluation.
    `(let ((,test-var ,item))
       (cond ,@(loop for (head . rest) in clauses
		   when (or (eq head t) (eq head 'otherwise))
		   collect `(t ,@rest)
		   else collect `((string= ,test-var ,head) ,@rest))))))


Tests:

  (macroexpand '(string-case "mystring"
		   ("fakestring" (print 'nope))
		   ("MYSTRING" (print 'nope))
		   ("mystring" (print 'yep))))
  (LET ((#:G137 "mystring"))
     (COND ((STRING= #:G137 "fakestring") (PRINT 'NOPE))
           ((STRING= #:G137 "MYSTRING") (PRINT 'NOPE))
           ((STRING= #:G137 "mystring") (PRINT 'YEP))))

  (string-case "mystring"
     ("fakestring" (print 'nope))
     ("MYSTRING" (print 'nope))
     ("mystring" (print 'yep)))

   ==>   YEP 
         YEP



-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Thomas F. Burdick
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <xcvbr0vxyr1.fsf@conquest.OCF.Berkeley.EDU>
J.C. Roberts <···············@abac.com> writes:

> (CASE ...) works fine when used with numbers or symbols but what I 
> don't understand is why it fails miserably on strings?

You mentioned in another thread that you mainly use SKILL, so one
thing you should watch out for in general with CL is that the default
comparison function is almost always EQL, not EQUAL.  Eg, CL's ASSOC
is SKILL's assq.  So in general, watch out for string comparisons.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | Free Mumia Abu-Jamal! |
     ,--'    _,'   | Abolish the racist    |
    /       /      | death penalty!        |
   (   -.  |       `-----------------------'
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Ken Tilton
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <ds81h.65690$td3.49659@newsfe08.lga>
J.C. Roberts wrote:
> #|
> 
> It seems I'm misunderstanding HyperSpec when it comes to the 
> (CASE ...) macro.
> 
> http://www.lisp.org/HyperSpec/Body/mac_casecm_ccasecm_ecase.html#case
> 
> I _think_ it is supposed to evaluate the keyform and then compare the
> result to the keys of the successive normal-clauses until it finds a 
> match (i.e with "the same" as defined by 
> http://www.lisp.org/HyperSpec/Body/glo_s.html#same)

"same adj. 1. (of objects under a specified predicate) indistinguishable 
by that predicate. ``The symbol car, the string "car", and the string 
"CAR" are the same under string-equal''. 2. (of objects if no predicate 
is implied by context) indistinguishable by eql."

Notice that eql is the default, and...

> 
> (CASE ...) works fine when used with numbers or symbols but what I 
> don't understand is why it fails miserably on strings?

.... (eql "aa" "aa") -> NIL

kt

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: ··········@gmail.com
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <1162253403.690465.32860@e64g2000cwd.googlegroups.com>
This would seem to work for many cases:

(defmacro mapcase (func-test keyform &body clauses)
	   `(cond ,@(loop for (test exec) in clauses collect
			  (if (or (eql test t) (eql test 'otherwise))
			      `(t ,exec)
			      `((funcall ,func-test ,keyform ,test) ,exec)))))

So the following can be used:
CL-USER> (mapcase #'string< "mystring2"
			  ("mystring" (princ "Winner!"))
			  ("mystring2" (princ "not good?"))
			  (otherwise (princ "...")))
...
"..."
CL-USER> (mapcase #'string> "mystring2"
			  ("mystring" (princ "Winner!"))
			  ("mystring2" (princ "not good?"))
			  (otherwise (princ "...")))
Winner!
"Winner!"
CL-USER> (mapcase #'string= "mystring2"
			  ("mystring" (princ "Winner!"))
			  ("mystring2" (princ "not good?"))
			  (otherwise (princ "...")))
not good?
"not good?"

... *crickets* party over, all went home ...
Jay
From: Bill Atkins
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <m2u01ko8r6.fsf@bertrand.local>
··········@gmail.com writes:

> This would seem to work for many cases:
>
> (defmacro mapcase (func-test keyform &body clauses)
> 	   `(cond ,@(loop for (test exec) in clauses collect
> 			  (if (or (eql test t) (eql test 'otherwise))
> 			      `(t ,exec)
> 			      `((funcall ,func-test ,keyform ,test) ,exec)))))
>
> So the following can be used:
> CL-USER> (mapcase #'string< "mystring2"
> 			  ("mystring" (princ "Winner!"))
> 			  ("mystring2" (princ "not good?"))
> 			  (otherwise (princ "...")))
> ...
> "..."
> CL-USER> (mapcase #'string> "mystring2"
> 			  ("mystring" (princ "Winner!"))
> 			  ("mystring2" (princ "not good?"))
> 			  (otherwise (princ "...")))
> Winner!
> "Winner!"
> CL-USER> (mapcase #'string= "mystring2"
> 			  ("mystring" (princ "Winner!"))
> 			  ("mystring2" (princ "not good?"))
> 			  (otherwise (princ "...")))
> not good?
> "not good?"
>
> ... *crickets* party over, all went home ...
> Jay

Each case can contain only one expression.  Also, I think the name
mapcase suggests that it is a higher-order function rather than a
language construct.
From: ··········@gmail.com
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <1162349495.782799.293990@b28g2000cwb.googlegroups.com>
Bill Atkins wrote:

> Each case can contain only one expression.  Also, I think the name
> mapcase suggests that it is a higher-order function rather than a
> language construct.

Yeah, I was kind of looking at generalizing the function further up
the (way back.. like last year...:) thread. I was kind of thinking that
"case" not working for strings could be considered a general problem
and could therefore be solved in a more general way (i.e. with a macro
which could be supplied a test function... so it's both, based on
another
Bill's definition of what "is" is... ;))

An improvement for multiple values:

(defmacro mapcase (func-test keyform &body clauses)
	   `(cond ,@(loop for (test exec) in clauses append
			  (if (or (eql test t) (eql test 'otherwise))
			      `(t ,exec)
			      (if (consp test)
				  (loop for atest in test collect
					`((funcall ,func-test ,keyform ,atest) ,exec))
				  `(((funcall ,func-test ,keyform ,test) ,exec)))))))

Such that:
CL-USER> (defparameter *my-test* #'(lambda (x y) (or (= x (* y y))
					   (= x (* y 2)))))
*MY-TEST*

CL-USER> (mapcase *my-test* 22
	   ((1 2 3 4 5 6 7) "Hit on first")
	   (11 "Hit on second"))
"Hit on second"

CL-USER> (mapcase *my-test* 25
	   ((1 2 3 4 5 6 7) "Hit on first")
	   (11 "Hit on second"))
"Hit on first"

And yep, it's not baked yet, gensyms.. multiple eval... possible other
nuance of case...
From: Bill Atkins
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <m21wonou0y.fsf@bertrand.local>
··········@gmail.com writes:

> And yep, it's not baked yet, gensyms.. multiple eval... possible other
> nuance of case...

But these aren't that hard to solve - the only place you have to watch
for multiple evaluation is in the keyform, so just gensym a variable
to hold the evaluation of the keyform, and bam, you've got a correct
and complete macro.
From: Raymond Laning
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <bbO1h.1$413.0@dfw-service2.ext.ray.com>
··········@gmail.com wrote:
> This would seem to work for many cases:
> 
> (defmacro mapcase (func-test keyform &body clauses)
> 	   `(cond ,@(loop for (test exec) in clauses collect
> 			  (if (or (eql test t) (eql test 'otherwise))
> 			      `(t ,exec)
> 			      `((funcall ,func-test ,keyform ,test) ,exec)))))
> 
> So the following can be used:
> CL-USER> (mapcase #'string< "mystring2"
> 			  ("mystring" (princ "Winner!"))
> 			  ("mystring2" (princ "not good?"))
> 			  (otherwise (princ "...")))
> ...
> "..."
> CL-USER> (mapcase #'string> "mystring2"
> 			  ("mystring" (princ "Winner!"))
> 			  ("mystring2" (princ "not good?"))
> 			  (otherwise (princ "...")))
> Winner!
> "Winner!"
> CL-USER> (mapcase #'string= "mystring2"
> 			  ("mystring" (princ "Winner!"))
> 			  ("mystring2" (princ "not good?"))
> 			  (otherwise (princ "...")))
> not good?
> "not good?"
> 
> ... *crickets* party over, all went home ...
> Jay
> 

I like this:

;;;Stringcase is like the regular case statement but does
;;;string match on keyform and clauses
(defmacro stringcase (match &rest patterns-and-actions)
   `(cond ,@(loop for (patt action) in patterns-and-actions
	         append (list
			 (list
			  (if (listp patt)
			      `(member ,match ',patt :test #'string=)
			      (if (eq patt t)
				  action
				  (list 'string= patt match))) action)))))

It has a couple of flaws - it evals match multiply, and I didn't put in 
the gensyms for the variable names so it's susceptible to variable 
capture, but otherwise does what the name implies
From: ········@comcast.net
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <1162693301.724752.44140@b28g2000cwb.googlegroups.com>
The first time I logged into this newsgroup, someone helped me with
this topic. I've been demoted to VisualBasic. Some of you will
understand why I miss the macro. And true inheritance. And a bunch of
other things.

M.

(defmacro case-equalp
    (keyform &body clauses)
  "
case-equalp

MACRO

---------------------------------------------------------------------

DESCRIPTION:

  A variation of the CL case macro using the equalp predicate.
  Conditionally evaluates the form of one of a group of
  key-and-clause forms.

SYNTAX:

  case-equalp KEYFORM {(KEY|({KEY}*) CLAUSE)}+

PARAMETERS:

  KEYFORM        ::= Lisp expression evaluating to a symbol, number,
                     or string.

  KEY            ::= Explicit symbol, number, or
                     string which are of the same types as KEYFORM.
                     This value is NOT evaluated.

  CLAUSE          ::= Standard Lisp form.

  Use the final key-and-clause form (t CLAUSE) or
  (otherwise CLAUSE) to provide a default
  expression.

EVALUATES-TO:

  Evaluates the first CLAUSE form where the evaluation of KEYFORM
  is equalp or member-equalp to KEY of the key-and-clause form.
"
  (loop with key-sym = (gensym)
      for (keys . forms) in clauses
      collect
        (if (or (eql keys 't) (eql keys 'otherwise))
            ;;;
            ;;; Construct the default clause to be evaluated.
            ;;;
            `(t ,@forms)
          ;;;
          ;;; Construct the 'key-symbol and expression
          ;;;
          (let ((key-list
                 ;;;
                 ;;; Each key-form pair assured to be
                 ;;; a keylist-form pair.
                 ;;;
                 (if (listp keys)
                     keys
                   (list keys))))
            `((or ,@(mapcar
                     #'(lambda (key) `(equalp ,key-sym (quote ,key)))
                     key-list))
              ,@forms)))
      into cond-clauses
      finally
        (return
          `(let ((,key-sym ,keyform))
             (cond
              ,@cond-clauses)))))
From: Sam Steingold
Subject: Re: Using (CASE ...) with strings?
Date: 
Message-ID: <m3ac36bjwy.fsf@loiso.podval.org>
> * J.C. Roberts <···············@nonp.pbz> [2005-11-06 00:26:31 -0800]:
>
> It seems I'm misunderstanding HyperSpec when it comes to the 
> (CASE ...) macro.
>
> http://www.lisp.org/HyperSpec/Body/mac_casecm_ccasecm_ecase.html#case
>
> I _think_ it is supposed to evaluate the keyform and then compare the
> result to the keys of the successive normal-clauses until it finds a 
> match (i.e with "the same" as defined by 
> http://www.lisp.org/HyperSpec/Body/glo_s.html#same)

as others have pointed out,
1. keyform is not evaluated
2. the comparison is with EQL, not EQUAL.

what you want it something like my FCASE:
http://clisp.cons.org/impnotes/flow-dict.html#fcase


-- 
Sam Steingold (http://sds.podval.org/) on Fedora Core release 5 (Bordeaux)
http://palestinefacts.org http://pmw.org.il http://camera.org
http://dhimmi.com http://mideasttruth.com http://truepeace.org
Press any key to continue or any other key to quit.