1

我的背景包括 10 年的通用 lisp,所以现在我正在学习 Clojure,方法是编写一个符号数学包,其中包含命名空间中的向量(即 a、b、c)和 Nvector 绑定(ab、ac、bc 等),并定义了 print 方法对于这些对象。

因此,当我在绑定函数所在文件的底部编写我的 deftests 时,我必须编写(声明 ab 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)))
        ))

...然后,当 (declare ab ab) 存在时,“已经引用:”编译器错误发生:

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

这个错误似乎有点过分,因为根据我的想法,“声明”实际上是编译器的“绑定承诺”,而没有真正定义一个。

有什么想法吗?

4

2 回答 2

1

declare不是那么聪明,它并没有真正创建以后会创建某些东西的承诺,而是现在创建它,并且它总是在本地命名空间中创建它,然后由你来确保它得到使用之前的值,否则当您尝试将未绑定的值用于需要绑定值的事物时将引发异常。def足够聪明,不会在先前定义的情况下用未绑定的值覆盖绑定值。

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

如您所见, declare declare 创建具有未绑定值的本地 var,正是此本地 var 创建触发了您看到的错误。因为命名空间 (` ns ) 表达式已经将具有该名称的条目添加到您的命名空间,所以当您的表达式:

 (declare a b ab) 

运行它将扩展到:

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

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

于 2013-10-22T23:04:53.373 回答
0

如果在同一个命名空间内完成,则可以按任意顺序定义和声明而不会出错。

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

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

于 2013-10-23T00:34:22.343 回答