我正在构建一个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)
答案 0 :(得分:4)
当你这样做时:
(word-to-number east num)
调用宏扩展器时参数为east
和num
。它们不是宏的列表和编号。仅对于生成的代码,它们将在产生值的上下文中进行评估。
宏是语法转换。例如。
(cond (p1 c1)
(p2 c2)
(t a))
; ==
(if p1
c1
(if p2
c2
a))
无论p1
是(< a b)
还是my-boolean-value
,都可以。宏只是将表达式放在那里,而不必知道a
,b
或my-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))