我是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和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 回答
Clojure中的编译单元是
s-expression
,而不是像许多其他语言一样的整个文件 . 加载文件 file is evaluated from top to bottom in a single pass 的文件时 . vars(通过调用def
创建的内容)必须在它们使用的位置上方创建,或者如果需要相互递归,则可以使用declare
,尽管这种情况很少见 .值得花一些时间习惯编译传统意义上的文件和加载lisp意义上的文件之间的区别,因为它是宏系统和语言的许多其他方面的基础 . 当您需要来自命名空间的文件,或者从repl调用
load-file
时,将调用clojure编译器并重复读取,宏扩展,然后从顶部开始对文件中的每个进行评估 . 第一行告诉它定义事物的名称空间,这就是ns
表达式首先出现的原因 . 然后,进一步的表单定义该命名空间中如果你再次加载文件,它只会再次从顶部读取文件 . 它不会清除命名空间或任何其他魔法,所以如果你评估文件,然后更改顺序并再次评估它可以继续工作,因为所需的函数已经在命名空间中定义(存储在memeory中)通过运行 . 当习惯这个时,经常运行_1545453会有所帮助,以确保订购顺序良好 .PS:绝大部分时间对
require
的调用都是在文件顶部的ns
表单中 .