13

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?

2
  • the term that describes what you're trying to do is that you're trying to define a pair of mutually recursive functions. I've edited your question to make that more clear. Commented Jul 9, 2010 at 14:23
  • @ken: thanks for correcting the terminology. Commented Jul 9, 2010 at 14:27

2 Answers 2

16

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

This is referred to as a "forward declaration".

Sign up to request clarification or add additional context in comments.

1 Comment

Then java.lang.IllegalStateException: Var user/is-prime is unbound. (NO_SOURCE_FILE:3) is thrown after typing (def primes (...)) line.
7

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?

3 Comments

BTW, there is also letfn to define mutually recursive functions.
2 is a prime number. It's only factors are 2 (itself) and 1.
@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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.