在Common Lisp中构建动态COND子句

时间:2019-02-22 15:21:42

标签: lisp common-lisp lisp-macros

我想知道是否有可能从(伪代码)这样​​的循环中动态构建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 :(得分:3)

宏会在编译时扩展,因此您的possible-states变量必须是编译时常量。如果不是这种情况(或者您对我的意思不是很清楚),则应在此处 not 使用宏。

改为使用函数

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

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

或者更好的是,将您的possible-states设为hash table,而不是association list

(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

请注意,从速度的角度来看,gethash版本可能与宏版本相同(至少它并不慢)。