Common lisp 如何在宏的帮助下定义一堆东西?

Common lisp 如何在宏的帮助下定义一堆东西?,common-lisp,sbcl,Common Lisp,Sbcl,我必须defconst64个值在我的程序中,并且鉴于Lisp拥有我至今从未使用过的著名宏工具,我认为这是我的机会。但它似乎不像我预期的那样起作用 (defun square-name (square-index) (multiple-value-bind (row col) (floor square-index 8) (format nil "SQ-~A~D" (string (code-char (+ (char-code #\A)

我必须
defconst
64个值在我的程序中,并且鉴于Lisp拥有我至今从未使用过的著名宏工具,我认为这是我的机会。但它似乎不像我预期的那样起作用


(defun square-name (square-index)
  (multiple-value-bind (row col) (floor square-index 8)
    (format nil "SQ-~A~D"
            (string (code-char (+ (char-code #\A) col)))
            (+ 1 row))))

(defmacro defconst-all-square-names ()
  (dotimes (i 64)
    `(defconstant ,(make-symbol (square-name i)) ,i)))
    
(defconst-all-square-names)

鉴于我对lisp和macros比较陌生,有人能解释一下吗

  • 如何实现定义这些常量的目标,而不必自己键入它们
  • 如果我不能使用宏,为什么
也许我只是错过了一些宣言之类的东西。上面的代码编译时没有警告或错误,加载后(使用emacs、slime和CTRL-C-K),没有定义任何常量

更新 在与@Rainer Joswig聊了一会儿(非常感谢!)之后发现, 那

  • 宏必须返回要执行的代码
  • 我使用
    (make symbol…
    的构造没有达到预期效果,我不得不使用
    (intern…
有了这些,工作代码现在看起来是这样的:

(defun square-name (square-index)
  (multiple-value-bind (row col) (floor square-index 8)
    (format nil "SQ-~A~D" (string (code-char (+ (char-code #\A) col))) (+ 1 row))))

(defmacro defconst-all-square-names ()
  (append '(progn)
      (loop for i from 0 to 63 collect
           `(defconstant ,(intern (square-name i)) ,i))))
    
(defconst-all-square-names)

让我们看一下时间:

* (dotimes (i 10) 42)
NIL
上面的
dotimes
表单返回
NIL
,与
()
->空列表相同。基本上它什么也不返回

因此,宏不返回任何内容。因此,代码
(defconst all square names)
扩展为
()
。用
macroexpand-1
检查是否正确

总而言之:

  • 你的宏没有副作用
  • 由于宏返回
    ()
你需要修复后者


记住:宏的第一个用途是生成代码。->您需要生成代码,否则需要键入。由于宏确实返回
()
,运行
()
自然不会产生任何效果->现在什么都不会发生。

让我们看看
dotimes

* (dotimes (i 10) 42)
NIL
上面的
dotimes
表单返回
NIL
,与
()
->空列表相同。基本上它什么也不返回

因此,宏不返回任何内容。因此,代码
(defconst all square names)
扩展为
()
。用
macroexpand-1
检查是否正确

总而言之:

  • 你的宏没有副作用
  • 由于宏返回
    ()
你需要修复后者


记住:宏的第一个用途是生成代码。->您需要生成代码,否则需要键入。由于宏返回
()
,运行
()
自然没有效果->什么也不会发生。

只有在我写
(defmacro defconst all square names()(从0到63循环收集
(defconstant,(make symbol(square name I)),它也不工作…@BitTickler
(foo)(foo)(foo))
在Common Lisp中不是有效代码。如果您打算生成一系列表单,那么您需要生成例如
(progn(foo)(foo)(foo))
(defmacro defconst all square names()(append(progn)(从0到63的循环collect`(defconstant,(make symbol(square name i)))不是吗…@bittickler:你怎么知道的?您是否使用了
macroexpand-1
查看生成的代码?如果您查看生成的代码,您可以很容易地看到另一个错误…让我们来看看。只有当我编写
(defmacro defconst all square names()(从0到63的循环collect
(defconstant,(make symbol(square name I)),I))`它也不工作…@BitTickler
((foo)(foo)(foo))
在Common Lisp中是无效的代码。如果您打算生成一系列表单,那么您需要生成例如
(progn(foo)(foo)(foo))
(defmacro defconst all square names()(append(progn)(从0到63的循环collect`(defconstant,(make symbol(square name i)))不是吗…@bittickler:你怎么知道的?您是否使用了
macroexpand-1
查看生成的代码?如果您查看生成的代码,您可以很容易地看到另一个错误…让我们来看看。