宏和阵列交叉

时间:2011-01-16 16:27:49

标签: macros common-lisp

我遇到了lisp宏的问题。我想创建一个宏 根据数组生成一个开关盒。

以下是生成switch-case的代码:

(defun split-elem(val)
  `(,(car val) ',(cdr val)))

(defmacro generate-switch-case (var opts)
  `(case ,var
     ,(mapcar #'split-elem opts)))

我可以使用这样的代码:

(generate-switch-case onevar ((a . A) (b . B)))

但是当我尝试做这样的事情时:

(defparameter *operators* '((+ . OPERATOR-PLUS)
                            (- . OPERATOR-MINUS)
                            (/ . OPERATOR-DIVIDE)
                            (= . OPERATOR-EQUAL)
                            (* . OPERATOR-MULT)))

(defmacro tokenize (data ops)
  (let ((sym (string->list data)))
    (mapcan (lambda (x) (generate-switch-case x ops)) sym)))

(tokenize data *operators*)

我收到了这个错误:*** - MAPCAR: A proper list must not end with OPS,但我不明白为什么。

当我打印ops的类型时,我得到SYMBOL我期待CONS,它是否相关?

另外,对于我的函数tokenize,lambda评估了多少次(或扩展了宏?)

感谢。

1 个答案:

答案 0 :(得分:1)

这没有任何意义。您尝试使用功能足够的宏。

你想要的是这样的:

(defun tokenize (data ops)
    (mapcar (lambda (d)
               (cdr (assoc d ops)))
            (string->list data)))

CASE是一个需要大量固定子句的宏。它不接受在运行时计算的子句。如果列表数据应驱动计算,则使用ASSOC等函数。

GENERATE-SWITCH-CASE也是一个奇怪的名字,因为宏是一个转换案例。

GENERATE-SWITCH-CASE也确实将列表作为第二个参数。但在TOKENIZE中,你用符号OPS称呼它。请记住,使用Lisp源代码计算宏。

接下来,还没有涉及ARRAY。 Lisp有数组,但在你的例子中没有数组。

典型建议:

  1. 如果你想写一个MACRO,请再想一想。把它写成一个函数。

  2. 如果你还想写一个宏,请转到1.