user1461328
user1461328

Reputation: 742

parameter evaluation of function call from a macro

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

Answers (3)

Kaz
Kaz

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

Rainer Joswig
Rainer Joswig

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

sds
sds

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

Related Questions