【问题标题】:Eval-when uses?eval-when 使用?
【发布时间】:2012-05-27 07:52:03
【问题描述】:

在阅读了大量有关 Lisp eval-when 运算符的文档后,我仍然无法理解它的用途,我知道使用此运算符我可以控制表达式的评估时间,但我无法找出任何可能的示例适用吗?

最好的问候, utxeee。

【问题讨论】:

    标签: compilation macros lisp common-lisp eval-when


    【解决方案1】:

    Lisp 文件的编译

    以 Lisp 文件的编译为例。 Lisp 编译器处理顶级表单。这些可以是任意的 Lisp 形式、DEFUN、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 的定义。因此,在以后文件编译器需要在BAZ的使用宏扩展过程中调用BAR时可用。

    只能使用:compile-toplevel,当文件编译后不需要该功能时。如果稍后使用它,那么我们需要确保它被加载。

    所以EVAL-WHEN 允许指定是否应该运行一段特定的代码

    • 文件编译期间
    • 在加载文件期间
    • 执行期间

    EVAL-WHEN 在用户代码中并不经常使用。如果你使用它,那么你应该问问自己是否真的需要它。

    【讨论】:

    • 嗨 Rainer,但是为什么我们在使用 eval-when 时需要使用标志 :execute 和 :load-top-level 呢?
    • Rainer 再次感谢您编辑上一个答案的回复:D 但我仍然怀疑,为什么我需要使用标志:load-top-level 和:execute。从您的文字中我可以看出,如果以后使用该功能,我们应该使用标志 :load-top-level 。那么为什么我们不需要在稍后将使用的所有其他函数中使用 eval-when 和 :load-top-level 呢?
    • @utxeee: load-top-level 是编译期间的默认值,当没有 EVAL-WHEN 时。
    • Rainer,还有两个问题:(1) - 如果我们已经使用您的示例从源代码加载了文件,则不需要使用 eval-when 运算符,因为 bar 定义是已知的, 正确的 ? (2) - 为什么我们需要使用关键字 :execute - 据我所知,这个关键字与运行时有关,但在运行时函数的定义也是已知的,对吧?
    • 能否请您改正错字load-top-level ==> :load-toplevel?我不得不深入研究源代码才能找到
    猜你喜欢
    • 1970-01-01
    • 2018-01-21
    • 2019-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-15
    相关资源
    最近更新 更多