如何让Lisp宏接收变量而非未加引号列表?字母算术求解器需求
解决字母算术求解器宏接收变量的问题
我懂你现在的困扰——你写的word-to-number宏目前只能处理字面量符号列表(比如直接写'(#\ #\E #\A #\S #\T)),但没法直接接收存储着符号列表的变量(比如你定义的east)。这是因为宏是在编译展开阶段工作的,原宏里的loop for symbol in symbols会试图在展开时遍历symbols的元素,但如果symbols是变量,此时它只是一个符号,不是实际的列表,自然会出错。
解决方案:让宏在运行时处理符号列表
我们需要修改宏的逻辑,把遍历符号列表的操作推迟到运行时,这样就能接收变量(或任何能返回符号列表的表达式)作为参数了。修改后的宏如下:
(defmacro word-to-number (symbols-expr lst) `(tonumber (loop for symbol in ,symbols-expr unless (eql symbol #\ ) collect (nth (position symbol *symbol-positions*) ,lst))))
代码解释
symbols-expr现在可以是任何能在运行时求值为符号列表的表达式(比如变量名east,或者更复杂的表达式)。- 宏展开后会生成一段运行时代码:遍历
symbols-expr求值后的列表,跳过空格字符,然后通过position找到每个符号在*symbol-positions中的索引,再从lst中取出对应的数字,最后传给tonumber。
测试示例
用你定义的变量测试:
(defparameter *symbol-positions* '(#\H #\T #\S #\R #\A #\U #\E #\O #\W #\N)) (defparameter num '(0 1 2 3 4 5 6 7 8 9)) (defparameter east '(#\ #\E #\A #\S #\T)) ;; 现在可以直接传入变量east了 (word-to-number east num)
优化建议:提升查找效率
如果你的字母算术问题涉及很多符号,position函数每次遍历*symbol-positions列表会有点慢。可以预先构建一个哈希表,把字符映射到对应的索引,这样查找速度会快很多:
;; 预先构建字符到索引的哈希表 (defparameter *char-to-index* (make-hash-table)) (loop for idx from 0 for char in *symbol-positions* do (setf (gethash char *char-to-index*) idx)) ;; 修改后的宏 (defmacro word-to-number (symbols-expr lst) `(tonumber (loop for symbol in ,symbols-expr unless (eql symbol #\ ) collect (nth (gethash symbol *char-to-index*) ,lst))))
这样每次查找字符对应的索引时,哈希表的gethash操作是O(1)的,比position的O(n)高效得多。
内容的提问来源于stack exchange,提问作者Gustav Bertram
相关产品推荐
相关产品推荐

