Reputation: 742
I have a function and one macro in which the function is called. And to see the difference, I trace the function and found that there was no difference whether it is called directly or from the macro. I wonder why the parameter was not evaluated when called from macro. I know that parameters passed to a macro will not be evaluated but even this happens to the parameters passed to a function from a macro? To be specific, I mean why (< 7 5) is not evaluated to nil when passed to gen-lisp
The function:
(defun gen-lisp (expr binds)
expr)
The macro:
(defmacro dsptch-prove-query (query binds)
`(if (eq (car ',query) 'lisp)
,(gen-lisp (cadr query) binds)
(prove-query ',query ,binds)))
Result when called from macro:
(dsptch-prove-query (lisp (< 7 5)) nil)
1. Trace: (GEN-LISP '(< 7 5) 'NIL)
1. Trace: GEN-LISP ==> (< 7 5)
NIL
Result when called directly:
(gen-lisp '(< 7 5) 'NIL)
1. Trace: (GEN-LISP '(< 7 5) 'NIL)
1. Trace: GEN-LISP ==> (< 7 5)
(< 7 5)
And if I just do it like this below, it is evaluated to nil already.
(gen-lisp (< 7 5) nil)
1. Trace: (GEN-LISP 'NIL 'NIL)
1. Trace: GEN-LISP ==> NIL
NIL
Upvotes: 1
Views: 270
Reputation: 58558
Your macro calls the function gen-lisp
at macro-expansion time in order to compute a part of the macro-expansion.
The expression which calls the function is this:
(gen-lisp (cadr query) binds)
this is a function call, which specifies two argument expressions: (cadr query)
and binds
. These expressions most certainly are evaluated as forms and their resulting values constitute the arguments which the function receives.
The macro's query
parameter's argument value is the nested list object (lisp (< 7 5))
and so (cadr query)
calculates the object (< 7 5)
. Of course this itself isn't evaluated as a form. Evaluation is done, and (< 7 5)
is its result, which gets passed into the function as its leftmost argument.
What's going on inside the macro is very similar to this:
(let ((query '(lisp (< 7 5))) ;; analogous to macro's query param
(binds nil))
(gen-lisp (cadr query) binds)) ;; of course (< 7 5) not evaled
If (< 7 5)
were reduced to nil
, that would be a double evaluation. Nothing in the code calls for a double evaluation. (For instance, we do not see any direct or indirect use of the eval
function which could request that extra evaluation).
Upvotes: 1
Reputation: 139251
Your macro is:
(defmacro dsptch-prove-query (query binds)
`(if (eq (car ',query) 'lisp)
,(gen-lisp (cadr query) binds)
(prove-query ',query ,binds)))
The macro calls the function gen-lisp
. The arguments are computed by (cadr query)
and binds
. query
is a list. (cadr query)
computes the second element of that list. That's the evaluation going on. There is no reason why it should evaluate the result of (cadr query)
.
Remember: macros are getting source code passed. They compute with code.
Just passing the code around does not evaluate the code.
Upvotes: 4
Reputation: 60004
gen-lisp
returns whatever argument it receives.
As a function, it does not evaluate its arguments.
If you want the argument to be evaluated, you should turn it into a macro (which you would probably want to do anyway when you start to use the binds
argument in non-trivial way)
Upvotes: 1