2010-08-08 10 views
7

Si yo lo siguiente en clojure¿Las dependencias cíclicas de la función clojure están específicamente deshabilitadas por diseño, o es solo un comportamiento del lector?

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    true (sub1b (- a 1)))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    true (sub1a (- a 1)))) 

(println (sub1a 10)) 

me sale el siguiente error:

java.lang.Exception: Unable to resolve symbol: sub1b in this context 

Pero si hago lo siguiente:

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    true (- a 1))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    true (- a 1))) 

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    true (sub1b (- a 1)))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    true (sub1a (- a 1)))) 

(println (sub1a 10)) 

Se ejecuta muy bien.

¿Es esto por diseño, o simplemente una función del funcionamiento del lector Clojure?

Respuesta

16

Usted puede hacer

(declare sub1a sub1b) 

'declare' está específicamente destinado a crear una var sin ataduras hacia adelante para hacer declaraciones.

Uno se declararon los nombres:

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    true (sub1b (- a 1)))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    true (sub1a (- a 1)))) 

(println (sub1a 10)) 

También la forma idiomáticas para especificar la condición por defecto en cond (por clojure) está utilizando el: cláusula else. Esto es un poco diferente de Common Lisp que usa T (para True). Para que su código anterior se pueda reescribir como:

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    :else (sub1b (- a 1)))) 

... 
3

La solución correcta es la publicada por rkrishnan.

En cuanto a esta parte de la pregunta:

Is this by design, or just a function of the way the Clojure reader works?

En realidad esto no es nada que ver con el lector Clojure - es porque el compilador resuelve símbolos a Vars inmediatamente después de encontrarse con ellos (en las posiciones en las que lo harían necesita "en última instancia" que se resuelva en Var, a diferencia de los lugares donde se nombra a los locales, se cotizan o se pasan a una forma especial o una macro, por supuesto). Esto tiene sentido por razones de eficiencia: saber a qué Var se refiere un símbolo en tiempo de compilación permite generar código que no necesita resolver símbolos en tiempo de ejecución (normalmente aún necesita buscar los valores de los Vars, pero no el Vars ellos mismos). Si realmente quisiera, podría tener sus símbolos de código a resolver en tiempo de ejecución:

(defn sub1a [a] 
    (cond 
    (= a 0) 0 
    :else ((resolve 'sub1b) (- a 1)))) 

(defn sub1b [a] 
    (cond 
    (= a 0) 0 
    :else ((resolve 'sub1a) (- a 1)))) 

(println (sub1a 10)) 

; prints 0 and returns nil 

Esto, sin embargo, causa una cierta degradación en el rendimiento, que casi nunca se justifica en código real, por lo tanto Clojure hace ser explícito acerca si usted realmente piensa que esto es lo que quiere.

Cuestiones relacionadas