【问题标题】:why can't I declare a namespace and a method in a do using Clojure为什么我不能使用 Clojure 在 do 中声明命名空间和方法
【发布时间】:2009-08-25 19:04:45
【问题描述】:

我尝试在 clojure 中编写一个宏来设置命名空间并自动向其中添加一些方法。我的宏不起作用,我将其追踪到一个 do 语句。不可能在 do 中声明一个新的命名空间,然后立即在该命名空间中声明一个方法。为什么?

这不起作用:

(ns xyz)
(do
  (ns abc)
  (prn *ns*)
  (defn tst[] (prn "test" *ns*)))

(prn "after" *ns*)
(tst)

这有效(在做之前的命名空间声明):

(ns xyz)
(ns abc)
(do
  (prn *ns*)
  (defn tst[] (prn "test" *ns*)))

(prn "after" *ns*)
(tst)

感谢阅读, 马库斯

【问题讨论】:

    标签: clojure namespaces


    【解决方案1】:

    实际上,您的代码恰好可以与 Clojure >1.0 一起使用,但不要依赖它! 每个顶级表单都被编译然后执行:

    (ns xyz) ; compiled with current ns / exec sets the current ns to xyz
    (do ; the whole form is compiled inthe current ns (xyz) so it defines xyz/tst
      (ns abc)
      (prn *ns*)
      (defn tst[] (prn "test" *ns*)))
    ; the form above is executed: it sets the new current ns 
    ; and the value for xyz/tst
    
    (prn "after" *ns*) ; we are in abc
    (tst) ; abc/tst doesn't exists
    

    在 clojure > 1.0 中,顶层的 a 是“展开”的,因此您的代码现在相当于:

    (ns xyz)
    ; (do
    (ns abc)
    (prn *ns*)
    (defn tst[] (prn "test" *ns*));)
    
    (prn "after" *ns*)
    (tst)
    

    【讨论】:

    • 啊,谢谢。这就解释了。一旦发布了稳定的 clojure 版本 > 1.0,我会牢记这一点。
    【解决方案2】:

    您的代码并没有像您认为的那样做。函数tst 将在函数运行时打印*ns*的值,一个var,而不是在定义时。

    user> (ns foobar)
    nil
    foobar> (abc/tst)
    "test" #<Namespace foobar>
    nil
    foobar> (ns zelsbot)
    nil
    zelsbot> (abc/tst)
    "test" #<Namespace zelsbot>
    nil
    

    clojure.contrib.with-ns 已经很好地提供了您正在尝试做的事情:

    (ns xyz
      (:use clojure.contrib.with-ns))
    
    (with-ns (create-ns 'abc)
      (defn tst [] (print "defined in namespace abc")))
    

    它在您作为第一个参数提供的命名空间中评估其主体,从而允许您将函数添加到当前命名空间之外的命名空间。

    【讨论】:

    • 这意味着作为运行时测试。无论如何,您的 with-ns 提示非常有用,因为我可以使用它来获得所需的功能。
    【解决方案3】:

    这是“宏扩展时间”时间与“运行时间”的问题。您是否希望 (do) 中的代码在程序编译或用户运行程序时发生?
    (ns ...) 行由阅读器扩展,然后由编译器用来决定将生成的编译代码放在哪里。
    如果我理解正确,ns 设置了 var 的顶级绑定,它告诉编译器的其余部分它正在构建代码的名称空间。作为一个实验,尝试考虑 (prn ...) 表达式应该进入哪个名称空间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-10
      • 1970-01-01
      • 2011-06-03
      • 2012-11-09
      • 2015-09-16
      • 2011-01-14
      • 2023-04-07
      相关资源
      最近更新 更多