2009-03-08 8 views
34

Je veux faire une instance locale d'une classe Java Scanner dans un programme de Clojure. Pourquoi ça marche pas:vs laissez-def dans clojure

; gives me: count not supported on this type: Symbol 
(let s (new Scanner "a b c")) 

mais il me permettra de créer une instance mondiale comme celui-ci:

(def s (new Scanner "a b c")) 

j'avais l'impression que la seule différence était portée, mais apparemment pas. Quelle est la différence entre let et def?

Répondre

48

Le problème est que l'utilisation de let est erroné.

Let fonctionne comme ceci:

(let [identifier (expr)]) 

Ainsi, votre exemple devrait être quelque chose comme ceci:

(let [s (Scanner. "a b c")] 
    (exprs)) 

Vous ne pouvez utiliser les liaisons lexicales faites avec let dans le cadre de let (l'ouverture et parens de clôture). Laissons juste créer un ensemble de liaisons lexicales. J'utilise def pour faire une liaison globale et permet de lier quelque chose que je veux seulement dans le cadre du let car cela garde les choses propres. Ils ont tous deux leurs usages.

NOTE: (. Class) est le même que (nouvelle classe), il est juste du sucre syntaxique.

+0

+1 pour les dernières lignes .. –

11

La syntaxe correcte:

(let [s (Scanner. "a b c")] ...) 
3

La syntaxe pour eux est différent, même si les significations sont liées.

prenons une liste de liaisons (paires de valeurs de nom) suivies d'expressions à évaluer dans le contexte de ces liaisons.

prend def une seule liaison, pas une liste, et ajoute au contexte mondial.

28

LET est pas « faire une fixation lexicale dans la portée actuelle », mais « faire 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 
+0

Je vois, donc un peu comme utiliser C# ou Python avec mais sans aucune destruction (ce qui serait un peu stupide étant donné l'état immuable de toute façon). –

7

simplifié: DEF est pour les constantes globales, nous est pour les variables locales.

+3

Non, c'est une simplification exagérée, et exactement cela a conduit à la confusion du demandeur initial.LET crée un nouveau bloc avec des liaisons lexicales, tandis que DEF ne fait qu'une nouvelle liaison "globale". – Svante

+0

Sonne mal pour moi. Def se lie toujours à Var et n'est donc pas une constante. Les liaisons d'espaces de noms peuvent également être modifiées, elles sont donc moins constantes. Let est une constante, il ne peut pas être changé ou re-binded du tout. Donc, à tout le moins, je dirais: "def est pour les variables globales, soit pour les constantes locales. –

0

Vous pourriez penser à let que le sucre syntaxique pour créer une nouvelle portée lexicale avec fn puis appliquer immédiatement:

(let [a 3 b 7] (* a b)) ; 21 
; vs. 
((fn [a b] (* a b)) 3 7) ; 21 

Vous pourriez mettre en œuvre let avec une simple macro et fn:

(defmacro fnlet [bindings & body] 
    ((fn [pairs] 
    `((fn [[email protected](map first pairs)] [email protected]) [email protected](map last pairs))) 
    (partition 2 bindings))) 

(fnlet [a 3 b 7] (* a b)) ; 21