clojure 函数循环依赖是设计明确禁止的,还是只是读者行为?
Posted
技术标签:
【中文标题】clojure 函数循环依赖是设计明确禁止的,还是只是读者行为?【英文标题】:Are clojure function cyclic dependencies specifically disallowed by design, or is it just a reader behaviour? 【发布时间】:2011-03-26 22:13:34 【问题描述】:如果我在 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 阅读器工作方式的一个功能?
【问题讨论】:
【参考方案1】:你可以的
(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) )))
...
【讨论】:
【参考方案2】:正确的解决方案是 rkrishnan 发布的。
至于这部分问题:
这是设计使然,还是只是 Clojure 阅读器工作方式的一个功能?
实际上,这与 Clojure 阅读器无关——这是因为编译器在遇到符号时会立即将符号解析为 Var(在那些需要“最终”解析为 Var 的位置,而不是在他们命名本地人,被引用或传递给特殊形式或宏,当然)。出于效率的原因,这是有道理的:在编译时知道符号指的是哪个 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 会让您明确说明这一点。 p>
【讨论】:
以上是关于clojure 函数循环依赖是设计明确禁止的,还是只是读者行为?的主要内容,如果未能解决你的问题,请参考以下文章