Dynamic variables in Lisp Case statement
I wrote this piece of code in common lisp (ignore the ... as it is pointless to paste that part here).
(case turn
(*red-player* ...)
(*black-player* ...)
(otherwise ...))
red-player and black-player are variables that were defined using defvar statement, in order to "simulate" a #define statement in C.
(defvar *red-player* 'r)
(defvar *black-player* 'b)
As you can imagine, when the variable turn
receives either *red-player*
's value ('r) or *black-player*
's value ('b), the case statement doesn't work properly, as it expects that turn contains *red-player*
as a literal, not the content of the variable *red-player*
.
I know that I can easily fix that us开发者_如何转开发ing a cond or if + equal statements, as the content of the variable is evaluated there, but I am curious. Maybe there is a way to create something like C's macros in Lisp, or there is some kind of special case statement that allows the use of variables instead of literals only.
Thank you in advance!
You can enter the value of expressions into your forms with read-time evaluation
CL-USER 18 > (defvar *foo* 'a)
*FOO*
CL-USER 19 > (defvar *bar* 'b)
*BAR*
CL-USER 20 > '(case some-var (#.*foo* 1) (#.*bar* 2))
(CASE SOME-VAR (A 1) (B 2))
Note that read-time evaluation is not necessarily the best idea for improving code maintenance and security.
Note also that the idea that there is a variable with a descriptive name for some internal value like is not necessary in Lisp:
dashedline = 4
drawLine(4,4,100,100,dashedline)
would be in Lisp
(draw-line 4 4 100 100 :dashed-line)
In Lisp one can pass descriptively named symbols. The sort of API that uses integer values or similar is only need in APIs to external software typically written in C.
The short answer is "yes, you can do it, sort of".
And the seeds of the longer answer involve the use of defmacro
to create your own version of case
, say mycase
, that will return a regular case
form. The macro you define would evaluate the head of each list in the case body.
You would call:
(mycase turn
(*red* ...)
(*black* ...)
(otherwise ...))
which would return
(case turn
((r) ...)
((b) ...)
(otherwise ...))
to the evaluator. The returned case
form would then be evaluated in the way you want.
You'd then be free to continue programming in your c-esque fashion to the dismay of lispers everywhere! Win-win?
You can abuse Lisp in any way you like. It is flexible like that, unlike C.
It doesn't always like the uses you put it to. Why push Lisp around?
Try this approach:
(defvar *turn* nil)
(cond
((eq *turn* 'red)
...
(setq *turn* 'black)))
((eq *turn* 'black)
...
(setq *turn* 'red)))
(t
.......))
精彩评论