function clojure dependencies cyclic

function - ¿Las dependencias cíclicas de la función clojure están específicamente prohibidas por el diseño, o es solo un comportamiento del lector?



dependencies cyclic (2)

Si hago lo siguiente en clojure

(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))

Obtuve 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))

Funciona bien.

¿Es esto por diseño, o solo una función de la forma en que funciona el lector Clojure?


La solución correcta es la publicada por rkrishnan.

En cuanto a esta parte de la pregunta:

¿Es esto por diseño, o solo una función de la forma en que funciona el lector Clojure?

En realidad, esto no tiene nada que ver con el lector de Clojure, es porque el compilador resuelve símbolos a Vars inmediatamente después de encontrarlos (en esas posiciones donde necesitarían "en última instancia" resolverse en Var, en lugar de lugares donde nombran a los locales , se citan o 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 hace posible generar código que no necesita resolver símbolos en tiempo de ejecución (todavía normalmente necesita buscar los valores de los Vars, pero no los Vars mismos ) Si realmente quisiera, podría hacer que su código resuelva símbolos 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 el código real, por lo tanto Clojure te hace ser explícito si realmente crees que esto es lo que quieres.


Tu puedes hacer

(declare sub1a sub1b)

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

Uno que declaró 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))

Además, la forma idónea de especificar la condición predeterminada en cond (para clojure) es usar la cláusula: else. Esto es un poco diferente de Common Lisp que usa T (para True). Entonces su código anterior puede ser reescrito como:

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