7

这个问题纯粹来自“精神主宰”,大概没有实用价值。

如果我在 Clojure 中使用 定义一个值def,是否可以诱导编译器在编译时评估它,而不是等到运行时?

(def the-answer 42)

(+ the-answer 1)

我想我可以定义一个宏,但是调用语法变得有点尴尬:

(defmacro the-answer [] 42)

(+ (the-answer) 1)

这也有效,但仍然很难看:

(+ `~the-answer 1)

我也理解(或相信)Clojure 在编译时计算常量表达式:

(def milliseconds-per-day (* 24 60 60 1000))

我只是在学习 Common Lisp,但我的理解是 Common Lisp 支持用户定义的阅读器宏,因此您可以定义一个阅读器宏(类似于#$),在编译时评估以下符号:

(+ #$the-answer 1)

顺便说一句,这种语法并不比宏调用“漂亮”。

如何让 Clojure 在编译时评估常量变量并将引用替换为实际值?它已经这样做了吗?

在有人开始引用 Knuth 定律(“过早优化是万恶之源”)之前,我问这个问题是为了更好地理解 Clojure 编译的内部结构。

4

3 回答 3

11

来自Clojure 1.3 文档

== 2.14 ^:常量定义 ==

^:const 允许您使用更快的引用命名原始值。

(定义常量 {:pi 3.14 :e 2.71})

(def ^:const pi (:pi 常数)) (def ^:const e (:e 常数))

在映射中查找 :e 和 :pi 的开销发生在编译时,因为 (:pi 常量) 和 (:e 常量) 在它们的父 def 形式被评估时被评估。

于 2011-11-10T15:32:42.660 回答
5

宏的主要用途之一是将计算转移到编译时间,因此它只执行一次。考虑到这一点,我认为宏是正确的工具,而且在我看来,它的额外( )外观实际上有助于使特殊部件看起来很特别。

于 2011-11-10T14:40:09.070 回答
2

`~foo从字面上看,foo在所有情况下都相同-您认为从前者中得到的任何东西都是一种错觉。

我认为:const可能是正确的答案,但您也可以使用 clojure.tools.macro 中的符号宏 - 它具有symbol-macroletdefsymbolmacro/with-symbol-macros用于此目的(以及其他用途)。

于 2011-11-14T02:07:24.903 回答