2013-08-24 15 views
6

È possibile definire due funzioni in clojure che si richiamano reciprocamente? Ad esempio, questa coppia:Due funzioni che si richiamano in modo ricorsivo

(defn a [x] 
    (if (= 0 x) 0 (b (dec x)))) 

(defn b [x] 
    (if (= 0 x) 0 (a (dec x)))) 

compilazione fallisce con:

Unable to resolve symbol: b in this context 

Non avendo definito b quando provo a richiamare in a.

per esempio, in ruby ​​questo funziona bene:

def a(x) 
    x == 0 ? x : b(x-1) 
end 

def b(x) 
    x == 0 ? x : a(x-1) 
end 

risposta

6

sia:

(declare b) ...; resto del codice può quindi essere utilizzato come è

o:

(def mutual 
(letfn [(a [ ... ] ...) 
     (b [ ... ] ...)] 
    [a b])) 

(def a (first mutual)) 
(def b (second mutual)) 
+0

Ha senso, immagino ci sia un compromesso per la velocità di compilazione che non può guardare avanti per le definizioni di funzione. Grazie alla risposta cancellata per questo link ai documenti (http://clojuredocs.org/clojure_core/clojure.core/declare) – spike

+0

Il compromesso non è per la velocità di compilazione, ma per gli errori di cattura. Esiste anche la funzione 'resolve' quando due namespace devono fare reciprocamente riferimento tra loro. – noisesmith

+0

Hai un link per maggiori informazioni a riguardo? Che tipo di errori vengono evitati dal compilatore ignorando le definizioni di funzioni esplicite? – spike

6

A seconda l'esecuzione del codice, tenere a mente che si potrebbe ottenere un'eccezione di overflow dello stack.

C'è una funzione (clojure.core/trampoline) che entra in gioco e fa la sua magia.

il trampolino può essere utilizzato per convertire algoritmi che richiedono reciproca ricorsione senza consumo di stack. Chiama f con argomenti forniti, se qualsiasi. Se f restituisce un fn, chiama fn senza argomenti e continua a ripetere finché il valore restituito non è un fn, quindi restituisce quel valore non-fn. Si noti che se si desidera restituire un valore fn come valore finale , è necessario avvolgerlo in una struttura dati e decomprimerlo dopo il ritorno del trampolino.

+0

ha! il primo post sul blog che ho trovato su questo ha utilizzato anche le mie funzioni di esempio: http://pramode.net/clojure/2010/05/08/clojure-trampoline/ – spike

Problemi correlati