我刚刚开始学习Common Lisp,我尝试了第一个Project Euler问题(将 x 下面的所有数字相加,可以被3或5整除)。我试图定义一个宏来将过程概括为可被给定的因子列表整除的数字,并遇到麻烦:当我运行宏时,它说有setf
的非法函数调用,并警告sum
未定义。其他人之前已经发布过这个问题并且在括号中出现了问题,但我举了一个例子,说明了我希望宏可以扩展到什么内容,并且该函数工作正常,括号完全在同一个地方。这是示例函数(工作正常)和宏(抛出错误)的代码:
;;; Example function for macro
(defun count-multiples-example (limit)
(let ((sum 0))
(dotimes (n (1+ limit) sum)
(dolist (each '(3 5))
(when (= 0 (mod n each))
(setf sum (+ n sum))
(return))))))
;;; Macro for arbitrary numbers to divide by (eventually)
(defmacro count-arbitrary (limit &rest divisors)
(let ((sum 0))
`(dotimes (n (1+ ,limit) ,sum)
(dolist (each ,divisors)
(when (= 0 (mod n each))
(setf sum (+ n ,sum))
(return))))))
我正在使用带有lispstick的SBCL。谢谢!
答案 0 :(得分:5)
CL-USER 28 > (defmacro count-arbitrary (limit &rest divisors)
(let ((sum 0))
`(dotimes (n (1+ ,limit) ,sum)
(dolist (each ,divisors)
(when (= 0 (mod n each))
(setf sum (+ n ,sum))
(return))))))
COUNT-ARBITRARY
让我们来看看扩展:
CL-USER 29 > (pprint (macroexpand-1 '(count-arbitrary 30 3 5)))
(DOTIMES (N (1+ 30) 0)
(DOLIST (EACH (3 5))
(WHEN (= 0 (MOD N EACH))
(SETF SUM (+ N 0)) (RETURN))))
您可以看到LET
变量的sum
缺失,(3 5)
缺少引号(因此是非法函数调用),sum
之前的逗号都是是错的。
通常,宏没有意义,因为您可以将数字作为函数的附加参数提供:
(defun count-multiples-example (limit divisors &aux (sum 0))
(dotimes (n (1+ limit) sum)
(dolist (each divisors)
(when (= 0 (mod n each))
(incf sum n)
(return)))))
或者这个:
CL-USER 35 > (defun count-multiples-example (limit &rest divisors &aux (sum 0))
(dotimes (n (1+ limit) sum)
(dolist (each divisors)
(when (zerop (mod n each))
(incf sum n)
(return)))))
COUNT-MULTIPLES-EXAMPLE
CL-USER 36 > (count-multiples-example 30 3 5)
225
答案 1 :(得分:1)
如果我将小点移动一点,这对我有用:
(defmacro count-arbitrary (limit &rest divisors)
`(let ((sum 0))
(dotimes (n (1+ ,limit) sum)
(dolist (each ',divisors)
(when (= 0 (mod n each))
(setf sum (+ n sum))
(return))))))