SmartyLisp
SmartyLisp

Reputation: 99

Build dynamic COND clauses in Common Lisp

I wonder if it is possible to dynamically build COND clauses from a loop like (pseudo code):

(defvar current-state 1)

(defmacro mymacro ()
  (cond
    `(loop (state . callback) in possible-states
      do ((eq current-state ,state)
          (funcall ,callback)))))

The LOOP would build the clauses from a list and generate something like:

(cond
  ((eq current-state 1)
   (funcall func-1))
  ((eq current-state 2)
   (funcall func-2))
  ((eq current-state 3)
   (funcall func-3)))

Upvotes: 0

Views: 174

Answers (1)

sds
sds

Reputation: 60014

Macros are expanded at compile time, so your possible-states variable has to be a compile-time constant. If this is not the case (or if you are not absolutely clear on what I mean above), you should not use a macro here.

Use a function instead:

(funcall (cdr (find current-state possible-states :key #'car :test #'eq)))

or

(funcall (cdr (assoc current-state possible-states :test #'eq)))

or, better yet, make your possible-states a hash table rather than an association list:

(funcall (gethash current-state possible-states))

However, if your possible-states is a compile time constant, you can, indeed, use a macro, except that you probably want to use case instead of cond:

(defmacro state-dispatch (state)
  `(case ,state
     ,@(mapcar (lambda (cell)
                 `((,(car cell)) (,(cdr cell))))
               possible-states)))
(defparameter possible-states '((1 . foo) (2 . bar)))
(macroexpand-1 '(state-dispatch mystate))
==> (CASE MYSTATE ((1) (FOO)) ((2) (BAR))) ; T

Note that from the speed point of view, the gethash version is probably identical to the macro version (at the very least it is not slower).

Upvotes: 3

Related Questions