我有一个函数和一个调用该函数的宏。 为了看到差异,我追踪函数并发现无论是直接调用还是从宏调用都没有区别。 我想知道为什么从宏调用时不评估参数。 我知道传递给宏的参数不会被评估,但即使这种情况发生在从宏传递给函数的参数中? 具体来说,我的意思是为什么(< 7 5)在传递给 gen-lisp
时未评估为 nil功能:
(defun gen-lisp (expr binds)
expr)
宏:
(defmacro dsptch-prove-query (query binds)
`(if (eq (car ',query) 'lisp)
,(gen-lisp (cadr query) binds)
(prove-query ',query ,binds)))
从宏调用时的结果:
(dsptch-prove-query (lisp (< 7 5)) nil)
1. Trace: (GEN-LISP '(< 7 5) 'NIL)
1. Trace: GEN-LISP ==> (< 7 5)
NIL
直接调用时的结果:
(gen-lisp '(< 7 5) 'NIL)
1. Trace: (GEN-LISP '(< 7 5) 'NIL)
1. Trace: GEN-LISP ==> (< 7 5)
(< 7 5)
如果我只是按照以下方式执行此操作,则会将其评估为 nil 。
(gen-lisp (< 7 5) nil)
1. Trace: (GEN-LISP 'NIL 'NIL)
1. Trace: GEN-LISP ==> NIL
NIL
答案 0 :(得分:4)
你的宏是:
(defmacro dsptch-prove-query (query binds)
`(if (eq (car ',query) 'lisp)
,(gen-lisp (cadr query) binds)
(prove-query ',query ,binds)))
宏调用函数gen-lisp
。参数由(cadr query)
和binds
计算。 query
是一个列表。 (cadr query)
计算该列表的第二个元素。那就是评估正在进行中。没有理由为什么它应该评估(cadr query)
的结果。
请记住:宏正在传递源代码。他们用代码计算。
只是传递代码不会评估代码。
答案 1 :(得分:1)
gen-lisp
返回它收到的任何参数。
作为一个函数,它不会评估它的参数。
如果你想要对参数进行求值,你应该把它变成一个宏(当你开始以非平凡的方式使用binds
参数时,你可能想要做的话)
答案 2 :(得分:1)
您的宏在宏扩展时调用函数gen-lisp
以计算宏扩展的一部分。
调用该函数的表达式是:
(gen-lisp (cadr query) binds)
这是一个函数调用,它指定了两个参数表达式:(cadr query)
和binds
。这些表达式肯定是被评估为表单,它们的结果值构成了函数接收的参数。
宏query
参数的参数值是嵌套列表对象(lisp (< 7 5))
,因此(cadr query)
计算对象(< 7 5)
。当然,本身不作为表格进行评估。评估已完成,(< 7 5)
是其结果,它作为最左边的参数传递给函数。
宏内部发生的事情与此非常相似:
(let ((query '(lisp (< 7 5))) ;; analogous to macro's query param
(binds nil))
(gen-lisp (cadr query) binds)) ;; of course (< 7 5) not evaled
如果(< 7 5)
缩减为nil
,那将是双重评估。代码中没有任何内容需要进行双重评估。 (例如,我们没有看到任何可以请求额外评估的eval
函数的直接或间接使用。)