I am learning Common Lisp (SBCL).
I want to create a facility to invoke two (or more) macros with several similar expressions that differ only in some parameters.
I would like to define the base of the expression, then modify it with the parameters I supply. For this a lambda function definition came to mind.
As far as I know, there is no analogue to funcall
for macros, so I've also wrapped the macros in lambdas.
I feel like I'm overcomplicating with with all these lambda
-s and funcall
-s. Is there a more elegant way?
The macros are from an external lib, so I'd prefer not to modify them.
(Specifically, the fiveam testing library's finishes
and signals
.)
Here is a sample code:
(defmacro macro1 (body) ())
(defmacro macro2 (body) ())
(defun check-expr-with-args (do-m func args)
(dolist (arg args)
(format t "~a " arg)
(funcall do-m (lambda () (funcall func arg)))))
(let ((test-expr
#'(lambda (val) (format t "~a" val)))
(cases (list
(list #'(lambda (func) ( macro1 (funcall func)))
(list 1 2 3 4 5))
(list #'(lambda (func) ( macro2 (funcall func)))
(list -4 -5 -6 -7 -8 -9)))))
(dolist (c cases)
(check-expr-with-args (first c) test-expr (second c))))
Originally I've tried to pass the macro names to my check-expr-with-args
function, and the expressions in quoted form, relying on lexical scoping for the parameter insertion. That didn't work out.
CodePudding user response:
I think you can write a wrapper macro that produces code that invokes macro1
(and macro2
). For example here I'm defining m1
that takes a test expression and another expression that is expected to evaluates at runtime to a list of values.
(defmacro m1 (test-expr input-expr)
(let ((arg (gensym)))
`(dolist (,arg ,input-expr)
(macro1 ,test-expr ,arg))))
Both test-expr
and input-expr
are injected in a dolist
expression, which binds a variable named arg
(a fresh symbol introduced with gensym
, to avoid capturing any existing one in the surrounding context).
For example:
(m1 (some-test-p) (list 1 2 3 4))
The above expands as:
(DOLIST (#:G1909 (LIST 1 2 3 4))
(MACRO1 (SOME-TEST-P) #:G1909))
The resulting expression contains MACRO1
, which will also be expanded. But it is now wrapped in an expression that iterates over some list computed at runtime (here, it could be a constant but you could replace it with any other expression).