From: Madhu on 4 Jan 2010 21:32 * (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 4 Jan 2010 21:50 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 4 Jan 2010 22:00 * 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 4 Jan 2010 22:27 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 4 Jan 2010 22:51
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 |