clojure - 不同命名空间中的eval代码

时间:2011-10-07 08:18:36

标签: namespaces clojure eval

我正在编写像REPL Server这样的代码。用户的请求评估此功能:

(defn execute [request]
  (str (try
          (eval (read-string request))
        (catch Exception e (.getLocalizedMessage e)))))

每个客户端都在单独的线程中。但它们具有相同的命名空间。如何在动态创建的命名空间中运行代码?因此,当新客户端连接时,我想创建新的命名空间并在那里运行客户端处理循环代码。或者也许可以在其他命名空间中运行(eval ..)

感谢。

UPD。
解决!

执行功能:

(defn execute  
  "evaluates s-forms"  
  ([request] (execute request *ns*))  
  ([request user-ns]  
    (str  
      (try  
        (binding [*ns* user-ns] (eval (read-string request)))  
        (catch Exception e (.getLocalizedMessage e))))))

每个客户端都通过以下方式获取自己的命名空间:

(defn generate-ns  
  "generates ns for client connection"  
  [] (let [user-ns (create-ns (symbol (str "client-" (Math/abs (.nextInt random)))))]  
    (execute (str "(clojure.core/refer 'clojure.core)") user-ns)  
    user-ns))`  

(defn delete-ns  
  "deletes ns after client disconnected"  
  [user-ns] (remove-ns (symbol (ns-name user-ns))))

offtop:如何在行开头的代码片段中进行偏移?

4 个答案:

答案 0 :(得分:15)

解决:

(binding [*ns* user-ns] (eval (read-string request)))

答案 1 :(得分:1)

更改名称空间意味着您必须重新初始化所有别名,或者使用完全限定名称引用clojure.core内容:

user=> (defn alien-eval [ns str]
         (let [cur *ns*]
           (try ; needed to prevent failures in the eval code from skipping ns rollback
             (in-ns ns)   
             (eval (read-string str))
             (finally 
               (in-ns (ns-name cur))
               (remove-ns ns))))) ; cleanup, skip if you reuse the alien ns
#'user/alien-eval
user=> (alien-eval 'alien "(clojure.core/println clojure.core/*ns*)") ; note the FQN
#<Namespace alien> ; the effect of println
nil                ; the return value of alien-eval

答案 2 :(得分:1)

  

(符号(str“client-”(Math / abs(.nextInt random)))

我只想补充一点,这可以用

来实现
(gensym "client-")

(我想发表评论,但它转变为我不能:))

答案 3 :(得分:0)

您可以编写一个模仿

的宏
(defmacro my-eval [s] `~(read-string s))

它比eval效果更好,因为s的符号解析发生在调用my-eval的上下文中。感谢@Matthias Benkard的澄清。