views:

74

answers:

2

How do I do mutually recursive definitions in Clojure?

Here is a code in Scala to find prime numbers which uses recursive definitions:

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

I translated this to 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)

But writing the definitions in the Clojure REPL one by one gives

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

after I write (def primes (cons 2 (filter is-prime odds))).

Is there a way to do mutually recursive definitions in Clojure?

A: 

You need to (declare is-prime) before the first time you reference it.

This is referred to as a "forward declaration".

Greg Harman
Then `java.lang.IllegalStateException: Var user/is-prime is unbound. (NO_SOURCE_FILE:3)` is thrown after typing `(def primes (...))` line.
abhin4v
+1  A: 

Greg's answer is correct. However you have to rearrange your code: (def odds ...) (declare primes) (defn prime-divisors ...) (defn prime? ...) (def primes ...). This should do the trick.

The problem is, that the definition of primes is not a function. It is executed immediately and hence tries to dereference the prime? Var which is not bound, yet. Hence the exception. Re-arranging should take care of that.

(Disclaimer: I haven't checked that the code works with the re-arrangement.)

And I think prime? is broken. (prime? 2) should give false, no?

kotarak
BTW, there is also letfn to define mutually recursive functions.
kotarak
2 is a prime number. It's only factors are 2 (itself) and 1.
Ken Bloom
thanks. that worked.
abhin4v
@Ken: I know that two is a prime number. And in the above `prime-divisors`: `(Math/ceil (Math/sqrt 2))` gives `2`. So the `2` from `primes` passes through the `take-while` and the `filter`. Hence in `(is-prime 2)` the return value of `prime-divisors` is not empty and false is returned. Ergo: `is-prime` is broken. I admit, that my formulation was a little unclear.
kotarak