阅读关于很多文档后Lisp的eval-when
操作者我仍然无法理解它的用途,我知道这个操作,我可以控制我的表达式的计算时间,但我想不通的地方,这可能是任何适用的例子吗?
最好的问候,utxeee。
阅读关于很多文档后Lisp的eval-when
操作者我仍然无法理解它的用途,我知道这个操作,我可以控制我的表达式的计算时间,但我想不通的地方,这可能是任何适用的例子吗?
最好的问候,utxeee。
一个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
未装入编译时环境。
有两个解决办法:
BAR
较早使用一个单独的文件。 例如用于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
不使用,往往在用户代码。 如果你使用它,那么你应该问问自己,如果你真的需要它。