Создание динамических предложений COND в Common Lisp - PullRequest
0 голосов
/ 22 февраля 2019

Интересно, можно ли динамически создавать предложения COND из цикла типа (псевдокод):

(defvar current-state 1)

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

LOOP будет строить предложения из списка и генерировать что-то вроде:

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

1 Ответ

0 голосов
/ 22 февраля 2019

Макросы раскрываются во время компиляции, поэтому ваша переменная possible-states должна быть константой времени компиляции.Если это не так (или если вы не совсем понимаете, о чем я говорю выше), вам следует не использовать здесь макрос.

Использовать функциювместо этого:

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

или

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

или, что еще лучше, создайте possible-states хэш-таблицу , а не список ассоциаций :

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

Однако, если ваша possible-states является постоянной времени компиляции, вы можете использовать макрос, за исключением того, что вы, вероятно, хотитеиспользовать case вместо 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

Обратите внимание, что с точки зрения speed , gethash версия, вероятно, идентична версии макроса (по крайней мере, она не медленнее).

...