So I would expect that I can use strings in a case statement.
I tried the following:
(defun do-command (this-command)
(case this-command
("d" (display-recipe-names))
(otherwise (format t "#~a# is an unknown command~%" this-command))))
But when feeding this "d" I get:
#d# is an unknown command
So properly I need to do something special to use strings. How would I
do this?
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
> I can not find much about case, but I found the following:
> case is a conditional that chooses one of its clauses to execute by
> comparing a value to various constants, which are typically keyword
> symbols, integers, or characters (but may be any objects).
>
> So I would expect that I can use strings in a case statement.
Indeed, you can.
> I tried the following:
> (defun do-command (this-command)
> (case this-command
> ("d" (display-recipe-names))
> (otherwise (format t "#~a# is an unknown command~%" this-command))))
>
> But when feeding this "d" I get:
> #d# is an unknown command
No, that's the problem. You are not feeding it THIS "d". You are
feeding it another "d".
Read closely clhs case, and notice what equality operator is used to
match the cases.
> So properly I need to do something special to use strings. How would I
> do this?
Here is a way to do it as you want:
C/USER[30]> (let ((this-d #1="d"))
(defun get-this-d () #1#)
(defun do-command (this-command)
(case this-command
(#1# (print '(display-recipe-names)))
(otherwise (format t "~S is an unknown command~%" this-command)))))
DO-COMMAND
C/USER[31]> (do-command (get-this-d))
(DISPLAY-RECIPE-NAMES)
(DISPLAY-RECIPE-NAMES)
C/USER[32]> (do-command #|another|#"d")
"d" is an unknown command
NIL
C/USER[33]>
Another way would be to intern the string (you don't want to do that
on strings comming from the outside word because of the risks of DOS
attacks), or go thru a hash-table, to identify the CASE, or just do
not use CASE, but COND or a STRING-CASE macro of your own or from a
library.
--
__Pascal Bourguignon__ http://www.informatimago.com/
> I can not find much about case, but I found the following:
> case is a conditional that chooses one of its clauses to execute by
> comparing a value to various constants, which are typically keyword
> symbols, integers, or characters (but may be any objects).
Well, the key item you need to consider for any of these comparison
constructs is to make sure you understand what predicate is used to do
the comparison for the selection of the items. From the HyperSpec:
"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."
So, now we need to know what "SAME" means in this context. The
HyperSpec definition that is relevant is the second one:
SAME: "... 2. (of objects if no predicate is implied by context)
indistinguishable by eql."
So that means that EQL is the test used for matching. And constant
strings with the same characters may or may not be EQL, and this can
differ depending on whether the function or file is compiled or not.
> So I would expect that I can use strings in a case statement.
>
> I tried the following:
> (defun do-command (this-command)
> (case this-command
> ("d" (display-recipe-names))
> (otherwise (format t "#~a# is an unknown command~%" this-command))))
>
> But when feeding this "d" I get:
> #d# is an unknown command
>
> So properly I need to do something special to use strings. How would I
> do this?
Yes. You either need to make sure that they are the same object (which
can be a bit tricky for strings but is doable), or you need to INTERN
the strings and use symbols (which is the easy way to make it work) or
you need to use one of the 3rd party utility libraries that implements a
different CASE-like statement that can handle strings.
Or, as an exercise in macro writing, you could write your own
STRING-CASE macro. That might be a nice learning exercise in its own
right.
One method of making it work would be:
(progn ;; Needed to have a single READER context
(defconstant D-COMMAND #1="d")
(defun do-command (this-command)
(case this-command
(#1# (format t "Found command ~A" this-command))
(otherwise (format t "#~a# is an unknown command~%" this-command)))))
But to use this, you need to specify the stored constant D-COMMAND:
(do-command d-command)
Found command d
NIL
(do-command "d")
#d# is an unknown command
NIL
So you can't use this to execute commands that you get, for example, by
reading in terminal input. To do that you would need to either intern
the string or use a different case structure.
There is actually a cleverer solution that uses a hash table and
registered functions that doesn't even use case at all. It is nicely
extensible and very general. And it is dead simple to implement in
Lisp.
--
Thomas A. Russ, USC/Information Sciences Institute
> Another way would be to intern the string (you don't want to do that
> on strings comming from the outside word because of the risks of DOS
> attacks),
What is the DOS attack scenario?
Exhaustion of memory by interning too many different strings?
Presenting really long strings to intern?
I suppose one way around that would be to use symbols as your keys and
then use FIND-SYMBOL on the incoming strings instead of INTERN. Would
that be safe against the DOS attack?
> p...@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Another way would be to intern the string (you don't want to do that
>> on strings comming from the outside word because of the risks of DOS
>> attacks),
>
> What is the DOS attack scenario?
>
> Exhaustion of memory by interning too many different strings?
> Presenting really long strings to intern?
Yes.
> I suppose one way around that would be to use symbols as your keys and
> then use FIND-SYMBOL on the incoming strings instead of INTERN. Would
> that be safe against the DOS attack?
Yes, FIND-SYMBOL would do.
| Cecil Westerhof <Ce...@decebal.nl> writes:
|> So I would expect that I can use strings in a case statement.
|
| Yes. You either need to make sure that they are the same object
| (which can be a bit tricky for strings but is doable), or you need to
| INTERN the strings and use symbols (which is the easy way to make it
| work) or you need to use one of the 3rd party utility libraries that
| implements a different CASE-like statement that can handle strings.
|
| Or, as an exercise in macro writing, you could write your own
| STRING-CASE macro. That might be a nice learning exercise in its own
| right.
A general solution is somewhat harder because of the various dimensions
that CASE abstraction specifies: 1. There is the relationship between
CASE and ECASE (sometimes you want to reach for ECASE). 2. There is
specified special handling of OTHERWISE (default, T) clauses in each
CASE and ECASE.
The other dimension is the TEST of course (I snipped out your discussion
on TEST above). The TEST for STRING-CASE can be STRING-EQUAL or
STRING-EQUALP. So you'd effectively be writing STRING-CASE-EQUAL or
STRING-CASE-EQUALP. So Perhaps CASE-EQUAL and CASE-EQUALP are more
useful abstractions than STRING-CASE.
To note my own Experience In my init file I have a rather hairy function:
function MAKE-CASE-EQUAL-FORMS (which &key (test 'equal) ecasep clauses)
Which I use to generate
(defmacro case-equal (which &body clauses)
(make-case-equal-forms which :test 'equal :ecasep nil :clauses clauses))
(defmacro ecase-equal (which &body clauses)
(make-case-equal-forms which :test 'equal :ecasep t :clauses clauses))
;; And to pass a user supplied TEST
(defmacro super-case ((which &key (test #'eql) ecasep) &body clauses)
"NOTE: May Evaluate TEST!"
(make-case-equal-forms which :test test :ecasep ecasep :clauses
clauses))
In the end I have always found it more appropriate to use a verbose COND
statement instead of SUPER-CASE. I'll avoid posting the hairy function
here.
[snip]
| There is actually a cleverer solution that uses a hash table and
| registered functions that doesn't even use case at all. It is nicely
| extensible and very general. And it is dead simple to implement in
| Lisp.
I think it might be useful (to the OP and me) if you gave a brief sketch
here.
--
Madhu
> I think it might be useful (to the OP and me) if you gave a brief sketch
> here.
I suspect it would be something like this:
(defvar *command-table* (make-hash-table :test #'equal))
(defun register-command (command fn)
(setf (gethash command *command-table*) fn))
(register-command "d" #'display-recipe-names)
;; more commands here
(defun do-command (command)
(let ((fn (gethash command *command-table*)))
(if fn
(funcall command)
(format t "~&~S is an unknown command.~%" command))))
Cheers,
Pillsy
| On Jan 4, 9:32 pm, Madhu <enom...@meer.net> wrote:
|> * (Thomas A. Russ) <ymiskalh3rc....@blackcat.isi.edu> :
| [...]
|> | There is actually a cleverer solution that uses a hash table and
|> | registered functions that doesn't even use case at all. It is
|> | nicely extensible and very general. And it is dead simple to
|> | implement in Lisp.
|
|> I think it might be useful (to the OP and me) if you gave a brief
|> sketch here.
|
| I suspect it would be something like this:
|
| (defvar *command-table* (make-hash-table :test #'equal))
|
| (defun register-command (command fn)
| (setf (gethash command *command-table*) fn))
[snip]
Sure, but what was not clear was not how you could store functions as
values of string keys in hash-tables and call them.
What was not clear was how this would be used: have you used this
technique in any situation where you might have reached for CASE to
define lexically scoped `action' forms ?
--
Madhu
It's embarrassing* to see everyone else in this list falling all over
themselves to give you what you want instead of helping you. The first
thing you need to learn is not to listen to anyone but me.
One of the best ideas in Lisp is that of the symbol. Use them. Not strings.
(do-command 'd)
...and...
(case cmd (d (display-recipe-names)))
If you get a string, quick, intern it.
kt
* But it /was/ funny to see the contorted monstrosities up with which
they came. kt
--
http://thelaughingstockatpngs.com/
http://www.facebook.com/pages/The-Laughingstock/115923141782?ref=nf
I'm not entirely sure how to answer this question, since I would have
reached for a hash-table with string keys as soon as I started writing
DO-COMMAND, without considering CASE.
> What was not clear was how this would be used: have you used this
> technique in any situation where you might have reached for CASE to
> define lexically scoped `action' forms ?
Yes. It's not hard to have the functions in the table take arguments,
and then you can explicitly pass them what they need in DO-COMMAND.
For the particular application of dispatching commands entered by the
user, the need to have some sort of consistent protocol for the
arguments the functions take seems like a pretty minor price to pay to
get the flexibility of the table-driven approach.
I can't imagine defining the functions using FLET/LABELS just because
that would be a (needless?) pain when it comes to testing and
debugging.
Cheers,
Pillsy
> Cecil Westerhof <Ce...@decebal.nl> writes:
>
> > I can not find much about case, but I found the following:
> > case is a conditional that chooses one of its clauses to
> > execute by comparing a value to various constants, which are
> > typically keyword symbols, integers, or characters (but may be
> > any objects).
> >
> > So I would expect that I can use strings in a case statement.
>
> Indeed, you can.
>
>
> > I tried the following:
> > (defun do-command (this-command)
> > (case this-command
> > ("d" (display-recipe-names))
> > (otherwise (format t "#~a# is an unknown command~%"
> > this-command))))
> >
> > But when feeding this "d" I get:
> > #d# is an unknown command
>
> No, that's the problem. You are not feeding it THIS "d". You are
> feeding it another "d".
Now that you put it that way, it all makes perfect sense. What was
I thinking? Thanks so much, Pasquale.
>
> Read closely clhs case, and notice what equality operator is used to
> match the cases.
>
> > So properly I need to do something special to use strings. How
> > would I do this?
>
> Here is a way to do it as you want:
>
>
> C/USER[30]> (let ((this-d #1="d"))
> (defun get-this-d () #1#)
> (defun do-command (this-command)
> (case this-command
> (#1# (print '(display-recipe-names)))
> (otherwise (format t "~S is an unknown command~%"
> this-command))))) DO-COMMAND
> C/USER[31]> (do-command (get-this-d))
>
> (DISPLAY-RECIPE-NAMES)
> (DISPLAY-RECIPE-NAMES)
> C/USER[32]> (do-command #|another|#"d")
> "d" is an unknown command
> NIL
> C/USER[33]>
>
>
>
> Another way would be to intern the string (you don't want to do that
> on strings comming from the outside word because of the risks of DOS
> attacks), or go thru a hash-table, to identify the CASE, or just do
> not use CASE, but COND or a STRING-CASE macro of your own or from a
> library.
You must decide whether you want to be productive and write clean
code or whether you want obsequiously to genuflect to the perversion
known as CL (CuLthu, CommuneLisp, CommodeLisp, etc.).
If your choice is the former, then you should be using Matzlisp (a.k.a.
Ruby):
def do_something this
case this
# String or symbol accepted.
when "d", :d
puts "Here, you'd display recipe names."
when /foo/
puts "How f'd up Commode Lisp is!"
else
puts "#{ this } is an unknown command"
end
end
do_something :d
do_something "d"
do_something "CL is foobarred."
do_something "?"
=== output ===
Here, you'd display recipe names.
Here, you'd display recipe names.
How f'd up Commode Lisp is!
? is an unknown command
Never forget what the honest, rational experts wrote about COBOL-LISP:
Bernard Lang:
Common Lisp did kill Lisp. Period. (just languages take a
long time dying ...) It is to Lisp what C++ is to C. A
monstrosity that totally ignores the basics of language
design, simplicity and orthogonality to begin with.
-----
Jeffrey M. Jacobs:
Common LISP is the PL/I of Lisps. Too big and too
incomprehensible, with no examiniation of the real world of
software engineering.
CL is a nightmare; it has effectively killed LISP
development in this country. It is not commercially viable
and has virtually no future outside of the traditional
academic/defense/research arena.
-----
Dick Gabriel:
Common Lisp is a significantly ugly language. If Guy and I
had been locked in a room, you can bet it wouldn't have
turned out like that.
-----
Paul Graham:
Do you really think people in 1000 years want to be
constrained by hacks that got put into the foundations of
Common Lisp because a lot of code at Symbolics depended on
it in 1988?
-----
Guy L. Steele, Jr., July 1989:
I think we may usefully compare the approximate number of pages
in the defining standard or draft standard for several
programming languages:
Common Lisp 1000 or more
COBOL 810
ATLAS 790
Fortran 77 430
PL/I 420
BASIC 360
ADA 340
Fortran 8x 300
C 220
Pascal 120
DIBOL 90
Scheme 50
--
Bigloo Scheme:
(match-case "d"
("d" (print "displaying recipes"))
(else (print "unknown command")))
--
A few solutions to your problem as I see it:
1. Use symbols instead of strings.
2. Make your own case-like macro which uses a hashtable.
It would be an interesting exercise
3. Use a more general construct like SWITCH from the arnesi library.
http://common-lisp.net/project/bese/docs/arnesi/html/api/macro_
005FIT.BESE.ARNESI_003A_003ASWITCH.html
You would use it like this:
(defun do-command (this-command)
(switch (this-command :test #'equal)
("d" (display-recipe-names))
(t (format t "#~a# is an unknown command~%" this-command))))
;; The switch would expand to:
(let ((#:g1110 this-command) (#:g1111 #'equal))
(cond ((or (funcall #:g1111 '"d" #:g1110))
(display-recipe-names))
(t (format t "#~a# is an unknown command~%" this-command))))
This shows that each test will be evaluated sequentially, which means
it's less efficient than the hashtable solution.
> (do-command 'd)
> ...and...
> (case cmd (d (display-recipe-names)))
> If you get a string, quick, intern it.
> kt
> * But it /was/ funny to see the contorted monstrosities up with which
> they came. kt
Like using FIND-SYMBOL instead of INTERN. Heathens!
Cheers,
Pillsy
> (defun do-command (this-command)
> (switch (this-command :test #'equal)
> ("d" (display-recipe-names))
> (t (format t "#~a# is an unknown command~%" this-command))))
Symbolics Common Lisp:
(defun do-command (this-command)
(scl:selector this-command equal
Now, Pillsy, we talked about you needing to read the notes:
"Notes: find-symbol is operationally equivalent to intern, except that
it never creates a new symbol."
So if you /get/ a string (say, the column name of a CSV file) quick,
intern it. Do not build a string version of Lisp.
Why do You People bother trying to correct me? Even EG/RG acknowledges
that I am the final arbiter of all things Lisp.
His Kennyness
--
> >> * But it /was/ funny to see the contorted monstrosities up with which
> >> they came. kt
> > Like using FIND-SYMBOL instead of INTERN. Heathens!
> Now, Pillsy, we talked about you needing to read the notes:
> "Notes: find-symbol is operationally equivalent to intern, except that
> it never creates a new symbol."
> So if you /get/ a string (say, the column name of a CSV file) quick,
> intern it. Do not build a string version of Lisp.
All the keys in the CASE statement were interned when the original
DEFUN was read.
That means that if you use INTERN on the user input, when the dingbat
using your cool CASE-based command loop types "svae" instead of
"save", you'll be the proud owner of the brand-new |svae| symbol. Whoo-
hoo?
> Why do You People bother trying to correct me?
USENET: where pedantry goes to die.
Cheers,
Pillsy
Don't exacerbate our already low opinion of you. The context was a
larger rule, something good teachers know about. You seem to be still
talking about the fish at hand.
>
> That means that if you use INTERN on the user input, when the dingbat
> using your cool CASE-based command loop types "svae" instead of
> "save", you'll be the proud owner of the brand-new |svae| symbol. Whoo-
> hoo?
>
>> Why do You People bother trying to correct me?
>
> USENET: where pedantry goes to die.
s/goes to/never/.
s/./s./.
kt
--
http://www.stuckonalgebra.com
"The best Algebra tutorial program I have seen... in a class by itself."
Macworld
>> USENET: where pedantry goes to die.
>
> s/goes to/never/.
> s/./s./.
"s.SENET: where pedantry never die."
"... think 'I know, I'll use a regex'. Now they have two problems"
-dan
> > All the keys in the CASE statement were interned when the original
> > DEFUN was read.
> Don't exacerbate our already low opinion of you.
It was one thing to learn that you don't like me, but to learn that
your tapeworm doesn't like me either?
:sob:
> The context was a
> larger rule, something good teachers know about. You seem to be still
> talking about the fish at hand.
Using FIND-SYMBOL instead of INTERN doesn't mean that you're making
your own screwy string-based Lisp, it just means that you only want to
handle a pre-defined inputs. Maybe you do, and maybe you don't, and it
really depends on what you were trying to do in the first place.
Some "larger rule" you got there.
Cheers,
Pillsy
> * But it /was/ funny to see the contorted monstrosities up with which
> they came. kt
Actually, I think the point of the contorted monstrosties was to
demonstrate that while you COULD make it work, you wouldn't want to.
I don't know, I think they meant it: this group has a long tradition of
robotically answering nooby questions as if somehow the noobs were
master Lisp programmers asking perfect questions. The only thing missing
was Costanza with a CLOS metaclass-based solution, or something that
took a simple case statement and exploded it into a bunch of scattered
metods, that would have been nice.
Where do I go to retract a fortune cookie?
kt
--
"There are no mediocre Lisp programmers." - kenny tilton
> Kenneth Tilton <kent...@gmail.com> writes:
>
>> Thomas A. Russ wrote:
>>> Kenneth Tilton <kent...@gmail.com> writes:
>>>
>>>> * But it /was/ funny to see the contorted monstrosities up with which
>>>> they came. kt
>>>
>>> Actually, I think the point of the contorted monstrosties was to
>>> demonstrate that while you COULD make it work, you wouldn't want to.
>>>
>>>
>> I don't know, I think they meant it: this group has a long tradition of
>> robotically answering nooby questions as if somehow the noobs were
>> master Lisp programmers asking perfect questions.
>
> Clearly, you don't understand the zen of cll...
>
>
>> The only thing
>> missing was Costanza with a CLOS metaclass-based solution, or something
>> that took a simple case statement and exploded it into a bunch of
>> scattered metods, that would have been nice.
>
> We didn't miss it, only it was latent. We explained how to use a
> hash-table. There are two ways to fill it:
>
> - either write a case-like macro that builds this hash-table at
> run-time (because of the clause body closures), but it wouldn't be
> efficient to build it each time...
>
> - or bit the bullet and just build that hash-table once for all
> explicitely, hence scatter the functions:
>
> (define-case-clause my-command-case "d" (parameter)
> (do-something-d parameter))
>
> (define-case-clause my-command-case "e" (parameter)
> (do-something-e parameter))
Couldn't one use LOAD-TIME-VALUE? For example:
(defun make-hash-to-integers (test args keyslist)
(let ((hash-table (apply #'make-hash-table :test test args))
(i 0))
(dolist (keys keyslist)
(dolist (key (if (atom keys) (list keys) keys))
(setf (gethash key hash-table) i))
(incf i))
hash-table))
(defmacro hash-ecase (keyform (&optional (test '(function eql)) &rest
args) &body cases)
"ECASE construct using a hash table. TEST specifies the test
function to use, ARGS is passed to MAKE-HASH-TABLE directly. The hash
table is constructed using LOAD-TIME-VALUE, and it is supposed to
contain constants only."
(let ((hash-table (gensym "HASH-TABLE")))
`(let ((,hash-table (load-time-value
(make-hash-to-integers ,test ,args ',(mapcar #'car cases)))))
(ecase (gethash ,keyform ,hash-table)
,@(let ((i 0))
(mapcar (lambda (case)
(prog1 `(,i ,@(cdr case))
(incf i)))
cases))))))
(defun test-hash-ecase (key)
(hash-ecase key (#'equal)
((1 2 3) :number)
(("foo" "bar") :string)
(symbol :symbol)))
(test-hash-ecase "bar")
(test-hash-ecase 3)
(test-hash-ecase 'symbol)
No bells/whistles (t/otherwise clause), but it could be done pretty
easily (eg mapping the default to 0 and starting numbering from 1).
There is a CASE left in there, but it is on a consecutive range of
integers, and most compilers should be able to optimize this very
easily.
Tamas
> Thomas A. Russ wrote:
>> Kenneth Tilton <kent...@gmail.com> writes:
>>
>>> * But it /was/ funny to see the contorted monstrosities up with which
>>> they came. kt
>>
>> Actually, I think the point of the contorted monstrosties was to
>> demonstrate that while you COULD make it work, you wouldn't want to.
>>
>
> I don't know, I think they meant it: this group has a long tradition
> of robotically answering nooby questions as if somehow the noobs were
> master Lisp programmers asking perfect questions.
Clearly, you don't understand the zen of cll...
> The only thing
> missing was Costanza with a CLOS metaclass-based solution, or
> something that took a simple case statement and exploded it into a
> bunch of scattered metods, that would have been nice.
We didn't miss it, only it was latent. We explained how to use a
hash-table. There are two ways to fill it:
- either write a case-like macro that builds this hash-table at
run-time (because of the clause body closures), but it wouldn't be
efficient to build it each time...
- or bit the bullet and just build that hash-table once for all
explicitely, hence scatter the functions:
(define-case-clause my-command-case "d" (parameter)
(do-something-d parameter))
(define-case-clause my-command-case "e" (parameter)
(do-something-e parameter))
...
(string-case my-command-case (read-line) argument)
> Where do I go to retract a fortune cookie?
Not "Where". When!
When you invent a time machine.
Nice.
This looked vaguely familiar. Compare this solution with Naggum's
WITH-HASHED-IDENTITY solution at
<http://groups.google.com/group/comp.lang.lisp/msg/a79ba3b04895a4d8>
Message-ID: <32086069...@naggum.net>
Date: Tue, 04 Sep 2001 15:43:06 GMT
Subject: Re: How can i make "case" to use equal?
From: Erik Naggum <er...@naggum.net>
--
Madhu
| * (Pascal J. Bourguignon) <873a2jt...@hubble.informatimago.com> :
| Wrote on Wed, 06 Jan 2010 19:37:18 +0100:
|
| | Tamas K Papp <tkp...@gmail.com> writes:
| |
| |> Couldn't one use LOAD-TIME-VALUE? For example:
[snip]
| | Nice.
|
| This looked vaguely familiar. Compare this solution with Naggum's
| WITH-HASHED-IDENTITY solution at
| <http://groups.google.com/group/comp.lang.lisp/msg/a79ba3b04895a4d8>
Actually with Tamas' integers-instead-of-object-identity simplification
one could eliminate the ECASE in the expanded form by compiling it into
an indexed lookup in an array.
IIRC Bradshaw posted a macro with that that idea, but I don't have it in
my cache.
--
Madhu
As Tamas mentionned, the compiler probably does that better.
| Madhu <eno...@meer.net> writes:
|> Actually with Tamas' integers-instead-of-object-identity simplification
|> one could eliminate the ECASE in the expanded form by compiling it into
|> an indexed lookup in an array.
|
| As Tamas mentionned, the compiler probably does that better.
Perhaps I was hoping someone would point me to Tim Bradshaw's macro.
Note that Tamas' code already does more than half of the work---by
generating consecutive numbers, generating the consecutive elements. So
it is really trivial to create a vector along with the load time
hash-table and avoid sequential lookup.
Maybe you can show some disassembly of a compiler which compiles the
CASE better?
--
Madhu
What do you want to store in the vector? Anonymous functions?
ciao,
Jochen
--
--
Jochen Schmidt
CRISPYLOGICS
Uhlandstr. 9, 90408 Nuremberg
mailto:(format nil "~(~36r@~36r.~36r~)" 870180 1680085828711918828 16438) http://www.crispylogics.com
| Perhaps. I was hoping someone would point me to Tim Bradshaw's macro.
| Note that Tamas' code already does more than half of the work---by
| generating consecutive numbers, generating the consecutive elements.
| So it is really trivial to create a vector along with the load time
| hash-table and avoid sequential lookup.
|
| What do you want to store in the vector? Anonymous functions?
You're right. I forgot about the CASE forms. Sorry
--
Madhu
> So properly I need to do something special to use strings. How would I
> do this?
The snazziest solution to this problem I use is