我的宏如何取一个变量而不是一个不带引号的列表?

时间:2018-04-04 22:12:08

标签: common-lisp

我正在构建一个alphametic解算器,我想制作一个用数字代替符号模板的宏。

以下是一个独立的示例:

(defparameter *symbol-positions* '(#\H #\T #\S #\R #\A #\U #\E #\O #\W #\N))

(defmacro word-to-number (symbols lst)
  `(tonumber (list ,@(loop for symbol in symbols
                           when (not (eql symbol #\ ))
                             collect `(nth ,(position symbol *symbol-positions*) ,lst )))))

(defparameter num '(0 1 2 3 4 5 6 7 8 9))
(defparameter east '(#\  #\E #\A #\S #\T))

以下调用有效:

(word-to-number (#\  #\E #\A #\S #\T) num)

但是这个没有:

(word-to-number east num) ;=> The value EAST is not of type LIST

有没有办法可以修改宏来为SYMBOLS参数取一个变量? ,symbols不起作用,`(,@symbols)

也不起作用

1 个答案:

答案 0 :(得分:4)

当你这样做时:

(word-to-number east num)

调用宏扩展器时参数为eastnum。它们不是宏的列表和编号。仅对于生成的代码,它们将在产生值的上下文中进行评估。

宏是语法转换。例如。

(cond (p1 c1)
      (p2 c2)
      (t a))

; ==

(if p1
    c1
    (if p2 
        c2
        a))

无论p1(< a b)还是my-boolean-value,都可以。宏只是将表达式放在那里,而不必知道abmy-boolean-value是什么。

请告诉我..扩展如何与(word-to-number east num)一起看?也许它根本不应该是一个宏观?例如。

(defun word-to-number (symbols lst)
  (tonumber (loop :for symbol :in symbols
                  :when (not (eql symbol #\ ))
                  :collect (nth (position symbol *symbol-positions*) lst))))

<强>更新

(defmacro word-to-number (symbols lst)
  `(tonumber (loop :for symbol :in ,symbols
                   :with clst := ,lst
                   :when (not (eql symbol #\ ))
                   :collect (nth (position symbol *symbol-positions*) clst))))

您可能会注意到我将lst存储在变量clst中,并在评估symbols后执行此操作。原因是,当您希望对参数进行求值时,您希望它们按顺序进行评估,并且只有一次,除非重复评估是像loop那样的宏的特征。例如。这应该只打印一次“哦,快乐的一天”:

(word-to-number (progn (princ "Oh") east) (progn (princ ", happy day!") num))