代码之家  ›  专栏  ›  技术社区  ›  Rob Lachlan

clojure编译器会在编译时自动计算文本的表达式吗?

  •  7
  • Rob Lachlan  · 技术社区  · 16 年前

    假设一个表达式只依赖于文本,或者其他表达式也只依赖于文本;编译器会在编译时对此进行计算吗?

    如果我有,

    (def a (some-time-consuming-function some-literal))
    
    (def b (some-other-time-consuming-function a))
    

    b和a是否会在编译时被完全计算,这样用户就不会受到影响?

    编辑6.6.2011: 结果表明,如果您尝试使用这种技术预计算一个非常大的数据结构,很容易使类文件太大而无法加载。在这些情况下,您希望创建一个将被读入的文件,而不是一个将被加载的类文件。这些答案中描述的宏技巧应该只在返回值不是一个非常大的结构的情况下应用。

    看到了吗 this thread

    4 回复  |  直到 15 年前
        1
  •  6
  •   Alex Taggart    16 年前

    一点也不傻,我得想一想,试一下。

    只有在使用宏而不是函数时,它才会起作用,因为宏的主体是在编译/宏扩展时计算的。例如。:

    (defmacro preprocess [f & args]
      (let [x# (apply (resolve f) args)]
        `~x#))
    
    (def a (preprocess some-time-consuming-function some-literal))
    
    (def b (preprocess some-other-time-consuming-function a))
    

    a b def 'd到计算返回的值 preprocess .

        2
  •  4
  •   Michał Marczyk    16 年前

    首先,有一个非常重要的原因是 def

    (def *available-processors* (.availableProcessors (Runtime/getRuntime)))
    

    其次,这里有一种测试实际情况的方法:

    1. 用Leiningen创建一个测试项目, lein new testdefs .

    2. :main testdefs.core project.clj .

    3. 将以下内容放入 src/testdefs/core.clj :

      (ns testdefs.core
        (:gen-class))
      
      (defn take-your-time [t]
        (printf "Taking my time (%d)...\n" t)
        (Thread/sleep t))
      
      (def a (take-your-time 5000))
      
      (defmacro frozen-def [v e]
        (let [val (eval e)]
          `(def ~v ~val)))
      
      (frozen-def b (take-your-time 5000))
      
      (defn -main [& args]
        (println "Starting...")
        (println a)
        (println b))
      
    4. lein uberjar

    5. java -jar testdefs-1.0.0-SNAPSHOT-standalone.jar ;您将注意到代码只占用一次时间。

        3
  •  3
  •   Stuart Sierra    16 年前

    在您的示例中,当您的代码被加载时,耗时的函数只被调用一次。

    Clojure编译器不尝试优化常量表达式,但是javajit编译器在某些情况下可能会这样做。

        4
  •  0
  •   Thumbnail    12 年前

    对于给定的示例,表达式在编译/加载时进行计算。 def 总是 计算其第二个参数。从 special forms

    (def symbol init?)
    

    创建并实习或定位名为的全局变量 symbol 以及当前名称空间值的名称空间 *ns* . init 提供时,将对其进行评估 ,并将var的根绑定设置为结果值。

    推荐文章