lisp非法函数调用

时间:2018-04-17 20:53:56

标签: common-lisp sbcl

我刚刚开始学习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。谢谢!

2 个答案:

答案 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))))))