Search code examples
macroslispcommon-lispclisp

Issues when write `loop ... collect` in macro


guys.

Today I want to write sigma macro to calculate the sum from the flexible expression input.

The code below is I written this afternoon. But it does not work follow my purpose.

(defmacro sigma (exp ll)
  `(+ ,@(loop for i in ll collect
             (progn (setf (elt exp 1) i)
                    (print exp)
                    exp)))
  )

>>(pprint (macroexpand-1 '(sigma (+ 1 2) (2 3 4))))
>>(+ 2 2) 
  (+ 3 2) 
  (+ 4 2) 
  (+ (+ 4 2) (+ 4 2) (+ 4 2))

I want it works (+ (+ 2 2) (+ 3 2) (+ 4 2)) but loop collect give me the weird answer.

Why does it work like this? Do I have some methods to fix this?


Solution

  • If you want a freshly consed list, then copy-list is a way:

    (defmacro sigma (exp ll)
      `(+ ,@(loop for i in ll and exp1 = (copy-list exp)
                  do (setf (second exp1) i)
                  collect exp1)))
    

    Nested backquote expressions are also possible:

    (defmacro sigma ((op arg0 &rest args) ll)
      (declare (ignore arg0))
      `(+ ,@(loop for i in ll collect `(,op ,i ,@args))))