Clojure中的相互递归定义

时间:2010-07-09 14:10:30

标签: clojure definition recursion

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

以下是Scala中用于查找使用递归定义的素数的代码:

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:

(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中逐一编写定义会给出

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中做相互递归的定义?

2 个答案:

答案 0 :(得分:7)

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

这被称为“前向声明”。

答案 1 :(得分:5)

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

问题是,素数的定义不是函数。它立即执行,因此尝试取消引用尚未绑定的prime? Var。因此例外。重新安排应该照顾好。

(免责声明:我没有检查代码是否适用于重新安排。)

我认为prime?已被打破。 (prime? 2)应该false,不是吗?