Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 using 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!

like image 374
Chocolatmisu Avatar asked Dec 18 '10 18:12

Chocolatmisu


2 Answers

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.

like image 110
Rainer Joswig Avatar answered Nov 13 '22 04:11

Rainer Joswig


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?

like image 4
Aliud Alius Avatar answered Nov 13 '22 04:11

Aliud Alius