Search code examples
lispcommon-lispclisp

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

Solution

  • 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).