在deftest中“声明”变量的Clojure编译错误

时间:2013-10-22 23:00:11

标签: clojure declare

我的背景包括10年的普通lisp所以现在我正在通过在名称空间中用向量(即a,b,c)和Nvector绑定(ab,ac,bc等)编写符号数学包来学习Clojure。为这些对象定义的print方法。

所以当我在与绑定函数相同的文件底部编写我的deftests时,我必须编写(声明一个b ab)来避免编译器警告(这很有道理)。

    (def G3 (doall (ga-bindall "a b c")))
    galg.core=> G3
    (+a +b +c +a*b +a*c +b*c +a*b*c +a*b +a*c +b*c +a*b*c)
    galg.core=> [a +a -a ab +ab -ab a*b +a*b -a*b abc]
    [+a +a -a +a*b +a*b -a*b +a*b +a*b -a*b a*b*c]

    (deftest galg-vectors
      (declare a b ab)   ;<=== required when in same file as definitions
      (testing "GALG Vector, Nvector and Sum tests."
        (is (= (Vector 'a) a))
        (is (= (Vector 'a -1) -a))
        (is (= ab (Nvector 'a 'b)))
        (is (= (+ 1 a ab) (Sum 1 a ab)))
        ))

然后当我通过将测试移动到galg.core-test文件来清理我的代码时,如下所示:

    (ns galg.core-test (:use clojure.test galg.core))  ;;<== imports a, b, ab, etc
    (deftest galg-vectors
      ;(declare a b ab)   ;<=== must be removed when in separate file 
      (testing "GALG Vector, Nvector and Sum tests."
        (is (= (Vector 'a) a))
        (is (= (Vector 'a -1) -a))
        (is (= ab (Nvector 'a 'b)))
        (is (= (+ 1 a ab) (Sum 1 a ab)))
        ))

...然后,&#34;已经提到:&#34;当(声明a b ab)存在时发生编译器错误:

CompilerException java.lang.IllegalStateException:a已经引用:#&#39; galg.core / a命名空间:galg.core-test,编译:(NO_SOURCE_PATH:2:3)

这个错误似乎有点过分,因为从我的想法,&#34;声明&#34;真的是一个约束力的承诺&#34;对于编译器,没有真正定义一个。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

declare并不那么聪明,它并没有真正创造出以后会创建某些内容的承诺,而是现在创建它,并且它始终在本地名称空间中创建它,然后将它留给您以确保它在使用之前获取值,否则当您尝试将未绑定值用于需要绑定值的值时,将抛出异常。 def足够智能,在先前已定义的情况下,不会使用未绑定的值覆盖绑定值。

user> (macroexpand-1 '(declare a))
(do (def a)) 

正如您所看到的,declare declare创建了具有未绑定值的本地变量,正是这个本地变量创建触发了您看到的错误。因为命名空间(` ns )表达式已经在命名空间中添加了一个带有该名称的条目,所以当你的表达式为:

 (declare a b ab) 

运行它将扩展为:

 (do (def a) (def b) (def ab))

将尝试在名为a的本地名称空间中创建一个var,该名称空间触发错误,因为该名称已引用另一个名称空间。

答案 1 :(得分:0)

如果在同一名称空间内完成,您可以无任何顺序def并声明而不会出错。

user> (def a 0)
#'user/a
user> (declare a)
#'user/a

问题是所有clojure变量都是命名空间。声明在调用它的命名空间中创建变量。因为您已调用use来引用另一个名称空间中的符号,所以声明它们会创建新变量galg.core-test/a等,这会影响您正在使用的变量,galg.core/a等。错误消息告诉你,由于use,一个不相关的var正在影响范围之前的那个。