7

如果我在 clojure 中执行以下操作

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (sub1b (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (sub1a (- a 1) )))

(println (sub1a 10))

我收到以下错误:

java.lang.Exception: Unable to resolve symbol: sub1b in this context

但是,如果我执行以下操作:

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (- a 1)))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (- a 1)))

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (sub1b (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (sub1a (- a 1) )))

(println (sub1a 10))

它运行得很好。

这是设计使然,还是仅仅是 Clojure 阅读器工作方式的一个功能?

4

2 回答 2

17

你可以做

(declare sub1a sub1b)

'declare' 专门用于创建一个没有绑定的 var 来进行前向声明。

你声明了一个名字:

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (sub1b (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (sub1a (- a 1) )))

(println (sub1a 10))

此外,在 cond(对于 clojure)中指定默认条件的惯用方式是使用 :else 子句。这与使用 T(表示 True)的 Common Lisp 有点不同。所以你之前的代码可以重写为:

(defn sub1a [a]
  (cond
    (= a 0) 0
    :else (sub1b (- a 1) )))

...
于 2010-08-08T10:53:11.997 回答
3

正确的解决方案由 rkrishnan 发布。

至于这部分问题:

这是设计使然,还是仅仅是 Clojure 阅读器工作方式的一个功能?

实际上,这与 Clojure 阅读器无关——这是因为编译器在遇到符号时立即将符号解析为 Vars(在那些需要“最终”解析为 Var 的位置,而不是他们命名 locals 的地方, 被引用或传递给特殊形式或宏,当然)。出于效率的原因,这是有道理的:在编译时知道符号引用哪个 Var 可以生成不需要在运行时解析符号的代码(它通常仍然需要查找 Vars 的,而不是 Vars 本身)。如果你真的想要,你可以让你的代码在运行时解析符号:

(defn sub1a [a]
  (cond
    (= a 0) 0
    :else ((resolve 'sub1b) (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    :else ((resolve 'sub1a) (- a 1) )))

(println (sub1a 10))

; prints 0 and returns nil

但是,这确实会导致性能下降,而这在实际代码中几乎是不合理的,因此如果您真的认为这是您想要的,Clojure 会让您明确这一点。

于 2010-08-08T18:40:45.980 回答