我正在构建一个字母解算器,我想制作一个将数字替换为符号模板的宏。
这是一个独立的示例:
(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)
也不起作用
最佳答案
当你这样做时:
(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))
关于common-lisp - 我的宏如何采用变量而不是不带引号的列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49661224/