【问题标题】:Build dynamic COND clauses in Common Lisp在 Common Lisp 中构建动态 COND 子句
【发布时间】:2019-07-16 17:32:36
【问题描述】:

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

【问题讨论】:

  • 建立一个列表,这不是mapcar 的用途吗?将列表拼接到位,可以使用,@
  • 如果你的状态是一个数字并且所有状态都是连续的,也许使用回调向量

标签: lisp common-lisp lisp-macros


【解决方案1】:

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

改用函数:

(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 版本可能与宏版本相同(至少不慢)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多