I am using SBCL, Slime, and Emacs to develop in Common Lisp.
I have this function:
(defun build-cond-action-pairs (&rest var)
(labels ((aux (xs-left accu)
(cond ((null (cddr xs-left))
(append accu (list (list (first xs-left)
(second xs-left)))))
(t (aux (cddr xs-left)
(append accu (list (list (first xs-left)
(second xs-left)))))))))
(aux var nil)))
I also defined these two variables:
CL-USER>(defparameter var-a 1)
VAR-A
CL-USER> (defparameter var-b 1)
VAR-B
When I call the function with:
CL-USER> (build-cond-action-pairs "fish are cool" (incf var-a) "amphibians are cool" (incf var-b))
As expected, the arguments are evaluated:
(("fish are cool" 2) ("amphibians are cool" 2))
I want to transform this function into a macro. Hence, the arguments will not be evaluated.
The desired output result would be:
(("fish are cool" (incf var-a)) ("amphibians are cool" (incf var-b)))
I tried with:
CL-USER> (defmacro macro-build-cond-action-pairs (&rest var)
`(labels ((aux (,xs-left ,accu)
(cond ((null (cddr ,xs-left))
(append ,accu (list (list (first ,xs-left)
(second ,xs-left)))))
(t (aux (cddr ,xs-left)
(append ,accu (list (list (first ,xs-left)
(second ,xs-left)))))))))
(aux ,var nil)))
But, it does not work:
; in: DEFMACRO MACRO-BUILD-COND-ACTION-PAIRS
; `(LABELS ((AUX (,XS-LEFT ,ACCU)
; (COND (# #) (T #))))
; (AUX ,VAR NIL))
; --> SB-IMPL::|List| SB-IMPL::|List| SB-IMPL::|List|
; ==>
; (SB-IMPL::|List| XS-LEFT ACCU)
;
; caught WARNING:
; undefined variable: COMMON-LISP-USER::ACCU
;
; caught WARNING:
; undefined variable: COMMON-LISP-USER::XS-LEFT
;
; compilation unit finished
; Undefined variables:
; ACCU XS-LEFT
; caught 2 WARNING conditions
MACRO-BUILD-COND-ACTION-PAIRS
Feels like a package (or namespace problem). Maybe the root is the labels part. I do not know how to solve it.
How can I fix this?
Thanks.
@Gwang-JinKim presented a solution (thanks for the help!). However, his solution changes the recursive approach described in my original answer.
I ended up finding a way to fix the macro keeping it very similar to the original question. Basically, it was necessary to remove some commas and to insert a (quote ...)
before the tail call.
Check it out:
CL-USER> (defmacro macro-build-cond-action-pairs (&rest var)
`(labels ((aux (xs-left accu)
(cond ((null (cddr xs-left))
(append accu (list (list (first xs-left)
(second xs-left)))))
(t (aux (cddr xs-left)
(append accu (list (list (first xs-left)
(second xs-left)))))))))
(aux (quote ,var) nil)))
It works:
CL-USER> (macro-build-cond-action-pairs "fish are cool" (incf var-a) "amphibians are cool" (incf var-b))
(("fish are cool" (INCF VAR-A)) ("amphibians are cool" (INCF VAR-B)))