From: Madhu on

* (Thomas A. Russ) <ymiskalh3rc.fsf(a)blackcat.isi.edu> :
Wrote on 04 Jan 2010 15:03:19 -0800:

| Cecil Westerhof <Cecil(a)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
From: Pillsy on
On Jan 4, 9:32 pm, Madhu <enom...(a)meer.net> wrote:
> * (Thomas A. Russ) <ymiskalh3rc....(a)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))

(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
From: Madhu on

* Pillsy <841473a4-6191-4df4-9ebe-885a091c1534(a)v7g2000vbd.googlegroups.com> :
Wrote on Mon, 4 Jan 2010 18:50:54 -0800 (PST):

| On Jan 4, 9:32 pm, Madhu <enom...(a)meer.net> wrote:
|> * (Thomas A. Russ) <ymiskalh3rc....(a)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
From: Kenneth Tilton on
Cecil Westerhof wrote:
> 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.
>
> 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?
>

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
From: Pillsy on
On Jan 4, 10:00 pm, Madhu <enom...(a)meer.net> wrote:
> * Pillsy <841473a4-6191-4df4-9ebe-885a091c1...(a)v7g2000vbd.googlegroups.com> :
[...]
> Sure, but what was not clear was not how you could store functions as
> values of string keys in hash-tables and call them.

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