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 函数循环依赖是设计明确禁止的,还是只是读者行为?的主要内容,如果未能解决你的问题,请参考以下文章

优化函数式编程:向 PHP 移植 Clojure 函数

如何使clojure程序结构更容易识别?

SpringBoot 2.6.0发布:禁止循环依赖,还有哪些实用的更新?

Clojure:如何在运行时找出函数的arity?

如何在 Clojure 中创建具有负指数的幂函数?

中文书籍中对《人月神话》的引用(十三):Clojure编程软件设计重构软件领导……