2010-07-09 7 views
4

Comment faire des définitions réciproquement réciproques dans Clojure?Définitions mutuellement récursives dans Clojure

Voici un code à Scala pour trouver des nombres premiers qui utilise des définitions récursives:

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 

Je traduis cela 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) 

Mais écrire les définitions du Clojure REPL un par un donne

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

après avoir écrit (def primes (cons 2 (filter is-prime odds))).

Existe-t-il un moyen de faire des définitions mutuellement récursives dans Clojure?

+0

Le terme qui décrit ce que vous essayez de faire est que vous essayez de définir une paire de fonctions * mutuellement * récursives. J'ai modifié votre question pour que ce soit plus clair. –

+0

@ken: merci de corriger la terminologie. –

Répondre

3

La réponse de Greg est correcte. Cependant, vous devez réorganiser votre code: (def odds ...) (declare primes) (defn prime-divisors ...) (defn prime? ...) (def primes ...). Cela devrait faire l'affaire.

Le problème est que la définition des nombres premiers n'est pas une fonction. Il est exécuté immédiatement et tente donc de déréférencer le prime? Var qui n'est pas encore lié. D'où l'exception. Réorganiser devrait prendre soin de cela.

:

Et je pense que prime? est cassé (Avertissement Je n'ai pas vérifié que le code fonctionne avec le réagencement.). (prime? 2) devrait donner false, non?

+0

BTW, il y a aussi letfn pour définir des fonctions mutuellement récursives. – kotarak

+4

2 est un nombre premier. C'est seulement les facteurs sont 2 (lui-même) et 1. –

+0

merci. ça a marché. –

6

Avant la première utilisation, vous devez indiquer (declare is-prime).

Ceci est appelé une "déclaration avant".

+0

Ensuite, 'java.lang.IllegalStateException: Var utilisateur/is-prime est unbound. (NO_SOURCE_FILE: 3) 'est lancé après avoir tapé' (def premiers (...)) 'line. –