lisp非法函数调用

1 sbcl common-lisp

我刚刚开始学习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))))))
Run Code Online (Sandbox Code Playgroud)

我正在使用带有lispstick的SBCL.谢谢!

Rai*_*wig 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
Run Code Online (Sandbox Code Playgroud)

让我们来看看扩展:

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))))
Run Code Online (Sandbox Code Playgroud)

你可以看到,LETsum变量缺失,(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)))))
Run Code Online (Sandbox Code Playgroud)

或这个:

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
Run Code Online (Sandbox Code Playgroud)