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
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
* 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>
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.
* 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>
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.
* 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>
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
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.)
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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
···@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
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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
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.