Clojure宏从文件中“插入”代码

时间:2013-10-19 11:38:17

标签: macros clojure

我有一个包含某些表单的文件,例如

(clojure.core/defn x [] (clojure.core/+ 5 7))
(clojure.core/defn y [a] (clojure.core/+ a 5))

我希望在运行之前将其“插入”另一个Clojure代码文件中。

据推测,我可以使用宏来做到这一点。我已经尝试编写一个读取文件并在字符串上调用load-string的宏,但这会导致在宏中直接评估表单。

即。鉴于上述文件,我想要

(some-other-code) ...

(my-macro)

(some-more-other-code)

扩展为

(some-other-code) ...

(clojure.core/defn x [] (clojure.core/+ 5 7))
(clojure.core/defn y [a] (clojure.core/+ a 5))

(some-more-other-code)

2 个答案:

答案 0 :(得分:4)

您可以使用内置的load函数执行此操作:

;; assuming foo.clj is on the classpath
(load "foo")

Clojure本身会将clojure.core分成几个文件,请参阅1.5.1版本源代码中紧跟this one之后的行。另请注意以这种方式加载的文件顶部的(in-ns 'clojure.core)

当然使用宏更灵活,因为它允许您在任意位置注入代码,以任意方式转换代码等。但是,如果您只想在多个文件之间分配命名空间,load会更简单。

答案 1 :(得分:3)

为什么不在想要引入这些功能的位置使用简单的(使用'命名空间)?

无论如何,这是我认为的诀窍代码:

(defn stream []
  (java.io.PushbackReader. (clojure.java.io/reader (clojure.java.io/file "foo.clj"))))

(defmacro insert []
  (let [content (with-open [s (stream)]
                  (loop [forms-so-far []]
                    (if-let [next-form (read s false nil)]
                      (recur (conj forms-so-far next-form))
                      forms-so-far)))]
    `(do ~@content)))