Clojure中的相互递归定义

Mutually recursive definitions in Clojure

如何在Clojure中进行相互递归定义?

这是Scala中的代码,用于查找使用递归定义的质数:

1
2
3
4
5
6
7
val odds: Stream[Int] = cons(3, odds map { _ + 2 })
val primes: Stream[Int] = cons(2, odds filter isPrime)
def primeDivisors(n: Int) =
    primes takeWhile { _ <= Math.ceil(Math.sqrt(n))} filter { n % _ == 0 }
def isPrime(n: Int) = primeDivisors(n) isEmpty

primes take 10

我将此翻译为Clojure:

1
2
3
4
5
6
7
8
9
(def odds (iterate #(+ % 2) 3))
(def primes (cons 2 (filter is-prime odds)))
(defn prime-divisors [n]
    (filter #(zero? (mod n %))
        (take-while #(<= % (Math/ceil (Math/sqrt n)))
            primes)))
(defn is-prime [n] (empty? (prime-divisors n)))

(take 10 primes)

但是在Clojure REPL中一个接一个地定义会给出

1
java.lang.Exception: Unable to resolve symbol: is-prime in this context (NO_SOURCE_FILE:8)

我写(def primes (cons 2 (filter is-prime odds)))后的

在Clojure中是否可以进行相互递归定义?


您需要在第一次引用它之前先(declare is-prime)

这称为"转发声明"。


格雷格的答案是正确的。但是,您必须重新排列代码:(def odds ...) (declare primes) (defn prime-divisors ...) (defn prime? ...) (def primes ...)。这应该可以解决问题。

问题在于,素数的定义不是函数。它会立即执行,因此尝试取消引用尚未绑定的prime? Var。因此,例外。重新安排应该注意这一点。

(免责声明:我尚未检查代码是否可以重新安排。)

我认为prime?坏了。 (prime? 2)应该给出false,不是吗?