在阅读了大量有关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
的定义,并且在编译时可用。因此,在需要在代码中调用BAZ
的宏扩展期间,BAR
也可以使用。
如果函数在文件编译完成后不再需要,则只需使用:compile-toplevel
即可。如果稍后需要使用它,则需要确保其已经被加载。
因此,EVAL-WHEN
允许指定特定代码段应该在何时运行:
EVAL-WHEN
在用户代码中并不经常使用。如果使用它,应该问自己是否真正需要它。
load-top-level
==>:load-toplevel
?我不得不深入源代码才找到它。 - ealfonso