【问题标题】:Clojure compile-time constantsClojure 编译时常量
【发布时间】:2011-12-26 03:35:21
【问题描述】:

本题纯属“脑补”,可能没有实用价值。

如果我在 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 在编译时评估常量变量并将引用替换为实际值?它已经这样做了吗?

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

【问题讨论】:

  • 这不是 pontification 是什么。冠冕堂皇就是夸夸其谈或教条。

标签: clojure compile-time-constant


【解决方案1】:

来自Clojure 1.3 docs

== 2.14 ^:const defs ==

^:const 让您可以更快地引用原始值。

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

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

在映射中查找 :e 和 :pi 的开销发生在编译时 时间,因为 (:pi 常数) 和 (:e 常数) 在它们的 评估父 def 表单。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 这是一个合理的答案,我也在想同样的事情。语法比 `~the-answer 更好。
    【解决方案3】:

    `~foo 在所有情况下都与foo 完全相同——无论你认为你从前者中得到了什么都是错觉。

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

    【讨论】:

    • 我没有意识到~foo. Thanks. As I think more about the problem, the ^:const` 似乎是正确的方法,但仅适用于原语(不包括String 实例)。字符串的问题在于,使用宏或 const 可能会导致运行时比较 String 内容而不是地址。如果这样做的原因是为了性能,那就是损失。
    猜你喜欢
    • 1970-01-01
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 2011-03-08
    • 2013-01-03
    相关资源
    最近更新 更多