Sono in grado di vedere 2 modi per implementare i collegamenti let
. Innanzitutto, come noto da SICP, let
può essere implementato come funzione lambda. Questo è comodo e semplice, ma tenendo conto del fatto che ogni lambda (fn
) viene tradotto in una classe separata in JVM e il numero di volte in cui viene utilizzato lo let
nel programma medio, sembra molto, molto costoso.Come viene implementato `let` in Clojure e qual è il suo overhead?
Secondo, let
associazioni possono essere convertite direttamente in variabili locali Java. Questo dà un sovraccarico molto piccolo, ma la memorizzazione dei binding su una pila infrange la semantica del linguaggio: in questo caso la creazione di chiusure è semplicemente impossibile - i valori salvati verranno distrutti subito dopo lo srotolamento dello stack.
Quindi, qual è l'implementazione effettiva utilizzata in Clojure? È apprezzato puntare a linee corrispondenti nella sorgente Clojure.
Quindi ho capito che l'oggetto di chiusura viene creato (e le variabili finali vengono copiate su di esso) solo quando necessario e per i casi in cui le vars rimangono solo nello stack? – ffriend
sì, è praticamente come funziona. Se sei interessato, puoi fare uno scavo in: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java (anche se non è particolarmente facile capire cosa sia Clojure il compilatore sta facendo, c'è un sacco di "magia") – mikera
@ffriend Java ha variabili con scope a blocchi (al contrario dell'ambito del metodo). Non ho visto cosa fa il compilatore Clojure ma sembra che * let * possa essere semplicemente implementato da un blocco di codice contenente variabili finali. Non sono sicuro del motivo per cui pensi che sarebbe stato implementato con una chiusura. –