Lisp - 在宏中使用逗号 (`,`)

Lisp - Utilisation of comma (`,`) in macro

我正在练习用 Elisp 编写宏。老师建议我们在“quasiquote”中包含程序的宏部分。

我想写一个宏“printCdrEach”来打印列表中 cdr 的每个元素(只是为了练习)

(defmacro print-cdr-each (first &rest rest)
  `(while (not (null ,rest))
    (eval (car ,rest))
     (setq rest (cdr ,rest)))
  )

(print-cdr-each 1 2 3 4) ; Expected Output 2 3 4

我不断收到错误“无效函数:2”。我确信编译器认为 2 是一个函数。但是,我不确定如何修复这个程序。

在不更改输入格式的情况下 (printCdrEach x x x x),在我的程序中“,”的正确用法是什么才能使其正常工作?

你应该试试 macroexpand-1:

(macroexpand-1 '(print-cdr-each 1 2 3 4))
; ==> (while (not (null (2 3 4))) 
;       (eval (car (2 3 4))) 
;       (setq rest (cdr (2 3 4)))) 
; ==> t
  • 表达式 (2 3 4) 无效。在 REPL 中尝试它,你会得到 eval: 1 is not a function name
  • 您多次使用 rest,因此如果它是一个表达式,它将被计算多次。

真的不需要宏:

(defun for-each (operation &rest elements)
  (loop :for e :in elements
        :do (funcall operation e)))

(for-each #'print 10 20)
10
20
; ==> nil

宏是语法糖。这意味着你应该能够说什么 (print-cdr-each 1 2 3 4) 应该扩展到代码中。由于您将其作为宏来执行,因此您可能希望将其扩展为静态:

(defmacro for-each (operation &rest elements)
  `(progn ,@(loop :for e :in elements 
                  :collect `(,operation ,e))))

(macroexpand-1 '(for-each print a b))
; ==> (progn (print a) (print b))
; ==> t

(let ((a 10) (b 20)) (for-each print a b))
10
20
; ==> 20