在-main中调用函数时的Clojure顺序依赖性

时间:2014-09-23 19:30:15

标签: clojure

我是Clojure的新手,我只想尝试构建一些示例应用程序以熟悉语法。我注意到以下顺序依赖行为。

我创建了一个名为timex的项目来计算两个日期之间的周数。我正在使用clj-time函数进行日期差异计算。

如果我的core.clj如下所示:

 (ns timex.core
  (:gen-class))
 (defn -main
  "Calculate weeks between dates."
  [& args]
  dp
   )
 (require '[clj-time.core :as t])
 (def d2 (t/date-time 1989 01 07))
 (def dw (t/in-weeks (t/interval d2 (t/now))))
 (def dp (str "The number of weeks between Jan 7, 1989 and now is " dw "!"))

**

如果我运行lein repl,我会收到以下错误:       #CompilerException java.lang.RuntimeException:无法在此上下文中解析符号:dp,编译:(timex / core.clj:4:1)

但是,如果我重新排序文件中的行并将def' s和require语句放在main之前

(ns timex.core
  (:gen-class))
 (require '[clj-time.core :as t])
 (def d2 (t/date-time 1989 01 07))
 (def dw (t/in-weeks (t/interval d2 (t/now))))
 (def dp (str "The number of weeks between Jan 7, 1989 and now is " dw "!"))
 (defn -main
  "Calculate weeks between dates."
  [& args]
  dp
   )

**

然后当我运行lein repl并调用(-main)函数时,我得到:

timex.core=> (-main)

"The number of weeks between Jan 7, 1989 and now is 1341!"

这种明显的顺序依赖正常还是我做错了什么?如果是后者,那么我将不胜感激任何我应该审查的建议或文件。感谢。

1 个答案:

答案 0 :(得分:3)

Clojure中的编译单元是s-expression,而不是像许多其他语言一样的整个文件。当您加载文件时,文件文件在一次传递中从上到下进行评估。 vars(通过调用def创建的内容)必须在使用它们的位置上方创建,或者如果需要相互递归,则可以使用declare,尽管这种情况很少见。

值得花一些时间习惯编译传统意义上的文件和加载lisp意义上的文件之间的区别,因为它是宏系统和语言的许多其他方面的基础。当您需要来自命名空间的文件,或从repl调用load-file时,将调用clojure编译器并重复读取,宏扩展,然后从顶部开始对文件中的每个进行评估。第一行告诉它定义事物的名称空间,这就是ns表达式首先出现的原因。然后,进一步的表单定义该命名空间中如果你再次加载文件,它只会再次从顶部读取文件。它不会清除命名空间或任何其他魔法,所以如果你评估文件,然后更改顺序并再次评估它可以继续工作,因为所需的函数已经在命名空间中定义(存储在memeory中)通过运行。习惯这个时,经常运行lein check有助于确保事情顺利进行。

PS:绝大多数情况下,对require的调用都是在文件顶部的ns表单中。