let vs def in clojure
Domanda
Voglio creare un'istanza locale di una classe Scanner
Java in un programma clojure. Perché questo non funziona:
; gives me: count not supported on this type: Symbol
(let s (new Scanner "a b c"))
ma mi permetterà di creare un'istanza globale come questa:
(def s (new Scanner "a b c"))
Avevo l'impressione che l'unica differenza fosse la portata, ma apparentemente no. Qual è la differenza tra let
e def
?
Soluzione
Il problema è che l'uso di let
è sbagliato.
Lascia che funzioni in questo modo:
(let [identifier (expr)])
Quindi il tuo esempio dovrebbe essere qualcosa del genere:
(let [s (Scanner. "a b c")]
(exprs))
Puoi usare solo le associazioni lessicali fatte con let nell'ambito di let (le parentesi aperta e chiusa). Lascia solo creare una serie di vincoli lessicali. Uso def per creare un'associazione globale e consente di rilegare qualcosa che voglio solo nell'ambito di let in quanto mantiene le cose pulite. Entrambi hanno i loro usi.
NOTA: (Class.) è uguale a (new Class), è solo zucchero sintattico.
Altri suggerimenti
LET non è "crea un legame lessicale nell'ambito corrente", ma "crea un nuovo ambito lessicale con i seguenti collegamenti".
(let [s (foo whatever)] ;; s is bound here ) ;; but not here
(def s (foo whatever)) ;; s is bound here
Sintassi corretta:
(let [s (Scanner. "a b c")] ...)
Semplificato: def è per le costanti globali, let è per le variabili locali.
La sintassi per loro è diversa, anche se i significati sono correlati.
let accetta un elenco di associazioni (coppie valore-valore) seguite da espressioni da valutare nel contesto di tali associazioni.
def accetta solo un binding, non un elenco, e lo aggiunge al contesto globale.
Potresti pensare a let
come zucchero sintattico per creare un nuovo ambito lessicale con fn
e applicarlo immediatamente:
(let [a 3 b 7] (* a b)) ; 21
; vs.
((fn [a b] (* a b)) 3 7) ; 21
Quindi puoi implementare let
con una semplice macro e fn
:
(defmacro fnlet [bindings & body]
((fn [pairs]
`((fn [~@(map first pairs)] ~@body) ~@(map last pairs)))
(partition 2 bindings)))
(fnlet [a 3 b 7] (* a b)) ; 21