如何在初始编译时间后使命名空间别名可用?

时间:2014-10-17 16:26:20

标签: clojure

我正在开发一个Clojure应用程序,它需要能够从shell命令行读取Clojure代码。该应用程序具有-main函数,该函数读取在命令行上传递的包含单个Clojure表单的字符串,并将此字符串传递给Clojure函数load-string,该函数解析字符串并执行代码。这使用lein run和使用uberjar成功运行。

我发现,如果名称空间位于包含required的文件顶部的-main,则命令行传递的代码可以包含完全限定的命名空间名称。例如,如果源文件以

开头
(ns popco.core.popco
  (:require [popco.core.reporters :as rpt]))

然后我在命令行上传递的字符串可以通过ticker引用我的函数popco.core.reporters/ticker。但是,我无法使用别名rpt。如果我ticker引用rpt/ticker,我会收到例外:java.lang.RuntimeException: No such namespace: rpt

我猜这是因为别名仅在编译时可用,并且只有一个编译时间。由于load-file编译代码字符串的时间是在完成源文件编译之后,rpt不再可用作别名。

允许我使用命名空间别名的解决方案是在require内复制文件顶部的-main(我想在repl中运行时使用)。但是,我可能需要包含几个名称空间,当然,复制代码也是不可取的。

还有其他解决方案吗?一些定义别名的方法,在repl中运行和从命令行运行代码时都可用吗?

(编辑:关于编译时间的分析可能非常正确 - 或者我可能不理解Clojure编译。(其实,我不理解Clojure汇编!)上面两段中提到的解决方案使用require内原始源代码中的-main语句,而不仅仅是传递给load-file的字符串。所以{{1}我想,在编译require时会编译,这会在与源文件顶部相同的传递过程中进行编译。但是-main中的某些代码在别名的范围内如果代码被输入到-main的定义中,则文件的顶部,但如果它是通过-main引入的,则不是。但是通过{{1}引入的是什么当load-file完全位于load-file的源代码中时,属于别名的范围。为什么?)

1 个答案:

答案 0 :(得分:1)

alias函数,该机制需要用于通过:as密钥创建命名空间别名,改变当前命名空间。也就是说,alias时的当前命名空间会运行。

这就是嵌入require定义的-main以您期望的方式创建别名的原因:它正在改变您的运行时命名空间以包含给定的别名。强调,这不一定会改变popco.core.popco命名空间!事实上,在调用-main时,它不可能是运行时的工作命名空间(它将在编译时,因此会像在ns宏中一样,改变被定义的ns。)

这里的关键是要意识到ns在运行时并不总是定义ns函数的-main,如果你想在运行时改变评估环境,那么你需要切换到您正在变异的命名空间,或者改变您所在的命名空间。