laisser vs def en clojure
Question
Je souhaite créer une instance locale d'une classe Java Scanner
dans un programme clojure. Pourquoi cela ne fonctionne-t-il pas:
; gives me: count not supported on this type: Symbol
(let s (new Scanner "a b c"))
mais cela me permettra de créer une instance globale comme celle-ci:
(def s (new Scanner "a b c"))
J'avais l'impression que la seule différence était la portée, mais apparemment pas. Quelle est la différence entre let
et def
?
La solution
Le problème est que votre utilisation de let
est incorrecte.
Laissé fonctionne comme ceci:
(let [identifier (expr)])
Votre exemple devrait donc ressembler à ceci:
(let [s (Scanner. "a b c")]
(exprs))
Vous ne pouvez utiliser que les liaisons lexicales faites avec let dans le cadre de let (parent et ouvrant). Laissons simplement créer un ensemble de liaisons lexicales. J'utilise def pour créer une liaison globale et permet de lier quelque chose que je veux uniquement dans le cadre de la let, car cela permet de garder les choses propres. Ils ont tous deux leur utilité.
NOTE: (Classe.) est identique à (nouvelle classe), c'est juste du sucre syntaxique.
Autres conseils
LET n’est pas "créer une liaison lexicale dans la portée actuelle", mais "créer une nouvelle portée lexicale avec les liaisons suivantes".
(let [s (foo whatever)] ;; s is bound here ) ;; but not here
(def s (foo whatever)) ;; s is bound here
Corrigez la syntaxe:
(let [s (Scanner. "a b c")] ...)
Simplifié: def concerne les constantes globales, let concerne les variables locales.
La syntaxe pour eux est différente, même si les significations sont liées.
let prend une liste de liaisons (paires nom-valeur) suivies d'expressions à évaluer dans le contexte de celles-ci.
def prend juste une liaison, pas une liste, et l'ajoute au contexte global.
Vous pourriez penser à laisser
comme un sucre syntaxique pour créer une nouvelle portée lexicale avec fn
puis l'appliquer immédiatement:
(let [a 3 b 7] (* a b)) ; 21
; vs.
((fn [a b] (* a b)) 3 7) ; 21
Vous pouvez donc implémenter laisser
avec une simple macro et 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