我的背景包括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;对于编译器,没有真正定义一个。
有什么想法吗?
答案 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正在影响范围之前的那个。