从宏开始的函数调用的参数评估

时间:2015-12-07 02:55:49

标签: lisp common-lisp clisp

我有一个函数和一个调用该函数的宏。 为了看到差异,我追踪函数并发现无论是直接调用还是从宏调用都没有区别。 我想知道为什么从宏调用时不评估参数。 我知道传递给宏的参数不会被评估,但即使这种情况发生在从宏传递给函数的参数中? 具体来说,我的意思是为什么(< 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

3 个答案:

答案 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函数的直接或间接使用。)