Basically I am trying to write a Common Lisp macro defined as:
(defmacro applyfunct (function arguments variables))
that applies the function given as the argument function
, to the argument arguments
(which is a list of arguments to apply the function to), that, when necessary, uses the variables given to it in the list of lists variables
. So the return value when it is called with these arguments like this:
(applyfunct + (7 5) ((x 1) (y 2)))
would be 12, considering that 7+5=12, and the context variable x and y were not needed to apply the function to the arguments. However when it does require the context variables given:
(applyfunct (lambda (x y) (+ (* a x) (* y b)) (4 2) ((a 2) (b 4))))
it should use these variables if they are needed in the function given to evaluate to return 16, because:
(applyfunct (lambda (x y) (+ (* a x) (* y b)) (4 2) ((a 8) (b 1))))
; 4 2 8 4 2 1
; (+ (* 8 4) (* 2 1)) => 34
hopefully my comments here make clear what I'm trying to do. What I have so far is:
(defmacro applyfunct (function arguments variables)
(let ( ((car (first contents)) (cdar (first contents))
((car (second contents)) (cdar (second contents))
but I have no idea how to proceed...
(apply function arguments)
would only work for the first example call where the function is +, not the second function call with the lambda. Am I missing something here? Should I be using ` or #' somehow? Note: I am trying to program as functionally as possible (minimal to no side effects, for example, not using setq). I am also using the CLISP implementation of Common Lisp.
As far as I know, apply
would only work for the second example (lambda
), not +
.
But remember that you're writing a macro, which can construct program code (such as (+ 7 5)
or ((lambda (x y) ...) 4 2)
) as needed.
The first step is to make the function call work (ignoring variables
for now). In Lisp, the syntactic form of a function call is a list whose first element (head) is the function and and whose remaining elements (tail) are the function arguments. This structure can be built e.g. by using cons
:
(defmacro applyfunct (function arguments variables)
(cons function arguments))
Or, using the syntactic sugar of `
:
(defmacro applyfunct (function arguments variables)
`(,function ,@arguments))
(`
acts like a code template, with ,
marking the spots where variables are to be inserted and ,@
additionally flattening the list.)
Now, to make variables
work, let
can be used to provide bindings (as in your code). However, there is no need to destructure variables
manually; it already has the right shape for a list of let
bindings:
(defmacro applyfunct (function arguments variables)
`(let ,variables
(,function ,@arguments)))
We can test this macro:
(print (macroexpand-1 '(applyfunct (lambda (x y) (+ (* a x) (* y b))) (4 2) ((a 8) (b 1)))))
; by the way, one of the ') is misplaced in your example: ----------^
Producing this output:
(LET ((A 8) (B 1)) ((LAMBDA (X Y) (+ (* A X) (* Y B))) 4 2))
... which is exactly what we want.