EVAL-时使用?(Eval-when uses?)

2019-07-29 11:28发布

阅读关于很多文档后Lisp的eval-when操作者我仍然无法理解它的用途,我知道这个操作,我可以控制我的表达式的计算时间,但我想不通的地方,这可能是任何适用的例子吗?

最好的问候,utxeee。

Answer 1:

一个Lisp文件的编译

就拿一个Lisp文件的汇编。 Lisp的编译器处理的顶级形式。 这些可以是任意的Lisp的形式,DEFUNs,DEFMACROS,DEFCLASS,函数调用,...

整个故事的文件编译器的工作原理是太复杂,在这里解释,但几件事情:

  • 文件编译器生成的码(DEFUN foo () )的形式。 不过,这并不执行defun定义形式。 因此,在编译时已经知道有一个函数FOO ,但在编译期间'FOO'的代码是不可用的。 编译器生成编译的文件中的代码,但不保存在内存中。 你不能在编译时称这样的功能。

  • 宏的工作方式略有不同: (DEFMACRO BAZ ...) 该文件编译器将不仅编译宏并注意它的存在,但它也将提供在编译时的宏。 它装载到编译环境

因此,想象在一个文件形式的序列:

(defmacro baz ...)

(defun foo () (baz ...))

这工作,因为该文件编译器知道宏观BAZ ,当它编译代码为FOO ,那么它可以扩展宏形式。

现在,让我们来看看下面的例子:

(defun bar (form) ...)

(defmacro baz (form) (bar form))

(defun foo () (baz ...))

上面将无法工作。 现在宏观BAZ使用函数BAR通过调用它。 当编译器试图编译功能FOO ,它不能扩大BAZ宏,因为BAR不能被调用,因为代码BAR未装入编译时环境。

有两个解决办法:

  1. 编译负载BAR较早使用一个单独的文件。
  2. 使用EVAL-WHEN

例如用于EVAL-WHEN

 (eval-when (:compile-toplevel :execute :load-toplevel)
   (defun bar (form) ...)
 )

 (defmacro baz (form) (bar form))

 (defun foo () (baz ...))

现在, EVAL-WHEN指令文件编译器在编译过程中实际运行defun定义形式。 这样做的结果是:该文件编译器现在知道的定义BAR编译时 。 因此,它是可后来,当文件编译需要调用BAR的使用的宏扩展期间BAZ

人们可以只使用:compile-toplevel ,当不会文件的编译后需要的功能。 如果以后使用,那么我们就需要确保它被加载。

因此, EVAL-WHEN允许指定如果一个特定的代码块应该运行

  • 文件的编译过程中
  • 文件加载期间,
  • 在执行过程中

EVAL-WHEN不使用,往往在用户代码。 如果你使用它,那么你应该问问自己,如果你真的需要它。



文章来源: Eval-when uses?