Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 从不同的命名空间运行嵌入式代码_Clojure_Namespaces - Fatal编程技术网

Clojure 从不同的命名空间运行嵌入式代码

Clojure 从不同的命名空间运行嵌入式代码,clojure,namespaces,Clojure,Namespaces,我经常希望在另一个名称空间中运行一小段代码—例如,可能是DSL代码的复制/粘贴片段,我希望避免: 在我当前的名称空间声明中添加一组use子句。这会使ns声明变得凌乱,增加额外的维护工作,有时还会出现名称冲突的风险 添加require子句,并强制向所有内容添加名称空间限定符或别名。现在我的DSL代码更混乱了 理想情况下,我更希望能够做到以下几点: (with-ns my.namespace (foo bar baz)) 其中foo,bar可能是my.namespace中的符号,但baz是

我经常希望在另一个名称空间中运行一小段代码—例如,可能是DSL代码的复制/粘贴片段,我希望避免:

  • 在我当前的名称空间声明中添加一组
    use
    子句。这会使ns声明变得凌乱,增加额外的维护工作,有时还会出现名称冲突的风险
  • 添加
    require
    子句,并强制向所有内容添加名称空间限定符或别名。现在我的DSL代码更混乱了
理想情况下,我更希望能够做到以下几点:

(with-ns my.namespace
  (foo bar baz))
其中
foo
bar
可能是
my.namespace
中的符号,但
baz
是当前(封闭)命名空间中的符号。因此,代码运行在类似“本地”名称空间的地方,该名称空间在其作用域内“使用”我的名称空间,但不会影响周围的名称空间


有没有标准/更好的方法来实现这一点?或者这是一件疯狂的事情吗?

这可以通过使用如下所示的宏来实现

注意:在某些情况下,它可能会断裂,因为我只是用一个简单的示例进行了尝试

;Some other ns
(ns hello)
(def h1 10) ;in hello
(def h2 11) ;in hello

;main ns in which executing code
(ns user)


(defmacro with-ns [target-ns body]
  (clojure.walk/postwalk
   (fn [val]
     (if (symbol? val)
       (if (resolve (symbol (str target-ns "/" val)))
         (symbol (str target-ns "/" val))
         val) val)) body))

(def u1 100) ;in user

(with-ns hello (do (+ h1 u1))) ;110
试试这个:

(defmacro with-ns [[namespace symbols] & body]
  `(do (use '[~namespace :only ~symbols])
       (let [result# (do ~@body)]
         (doseq [sym# (map #(:name (meta (val %)))
                           (filter #(= (name '~namespace)
                                       (str (:ns (meta (val %)))))
                                   (ns-refers *ns*)))]
           (ns-unmap *ns* sym#))
         result#)))

(with-ns [clojure.string [split upper-case]]
  (split (upper-case "it works!") #" "))
-> ["IT" "WORKS!"]

工作结束后,它会从当前的ns中删除使用过的符号。

我最终在旧的Clojure contrib中找到了一个宏,该宏相当巧妙地完成了部分工作:

(defmacro with-ns
  "Evaluates body in another namespace.  ns is either a namespace
  object or a symbol.  This makes it possible to define functions in
  namespaces other than the current one."
  [ns & body]
  `(binding [*ns* (the-ns ~ns)]
     ~@(map (fn [form] `(eval '~form)) body)))

我使用load file(加载文件)来实现这一点,这是一个黑客行为:-/所以你不是唯一的一个,这可能仍然很疯狂。@Arthur-hmm看到了这一点,但代码片段通常不在一个自包含的文件中,而且在我们不需要的时候,这似乎是对文件系统的滥用。顺便说一句,很高兴在Conj见到你!这是一个限制,因为DSL使用(在我的例子中,网络+虚拟机定义需要每个文件一个,所以这不是一个好的答案。很高兴见到你:)我认为这个解决方案的一个大缺点(至少在它当前的形式下)是它将取代任何嵌套的“let”块中绑定的符号。但仍然是我的+1。这不是解决方案,因为在临时名称空间“ns”中没有来自当前ns(在您的示例中为“baz”)的符号。或者您的问题只是关于临时完整名称空间切换,而不访问当前ns中的符号?您可以调整宏以引用其他名称空间。