2009-03-08 14 views
34

Ich möchte eine lokale Instanz von Java Scanner Klasse in einem Clojure-Programm machen. Warum funktioniert das nicht:let vs def in clojure

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

aber es lässt mich eine globale Instanz wie folgt erstellen:

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

Ich hatte den Eindruck, dass der einzige Unterschied war, Umfang, aber anscheinend nicht. Was ist der Unterschied zwischen let und def?

Antwort

48

Das Problem ist, dass die Nutzung von let falsch ist.

Let funktionieren wie folgt:

(let [identifier (expr)]) 

So Ihr Beispiel so etwas wie dies sein sollte:

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

Sie nur die lexikalischen Bindungen gemacht let im Rahmen von let verwenden kann (die Öffnung und schließende Parens). Lassen Sie nur eine Reihe von lexikalischen Bindungen erstellen. Ich benutze def, um eine globale Bindung zu machen, und lässt etwas binden, das ich nur im Rahmen der Vermietung haben möchte, da es die Dinge sauber hält. Sie haben beide ihren Nutzen.

HINWEIS: (Klasse.) Ist das gleiche wie (neue Klasse), es ist nur syntaktischer Zucker.

+0

+1 für die letzten Zeilen .. –

11

korrekte Syntax:

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

Die Syntax für sie ist unterschiedlich, auch wenn die Bedeutungen verwandt sind.

Lassen Sie eine Liste der Bindungen (Name Wert Paare), gefolgt von Ausdrücken im Rahmen dieser Bindung zu bewerten.

def nimmt nur eine Bindung, keine Liste, und fügt sie dem globalen Kontext hinzu.

28

LET ist nicht "mache eine lexikalische Bindung im aktuellen Gültigkeitsbereich", sondern "lege einen neuen lexikalischen Geltungsbereich mit den folgenden Bindungen fest".

 
(let [s (foo whatever)] 
    ;; s is bound here 
) 
;; but not here 
 
(def s (foo whatever)) 
;; s is bound here 
+0

Ich sehe, so ähnlich wie C# verwendet oder Python mit aber ohne jegliche Zerstörung (die wäre irgendwie dumm angesichts unveränderlichen Zustand sowieso). –

7

Vereinfacht: def ist für globale Konstanten, lassen für lokale Variablen ist.

+3

Nein, das ist eine Vereinfachung, und genau das führte zur Verwirrung des ursprünglichen Fragestellers.LET erstellt einen _new_block_ mit lexikalischen Bindungen, während DEF nur eine neue "globale" Bindung erstellt. – Svante

+0

Klingt falsch für mich. Def bindet immer an einen Var und ist somit keine Konstante. Namespace-Bindungen können ebenfalls geändert werden, sodass sie noch weniger konstant sind. Sei eine Konstante, sie kann nicht verändert oder neu gebunden werden. Also würde ich zumindest sagen: "def ist für globale Variablen, lass es für lokale Konstanten sein. –

0

könnten Sie denken an let als syntaktischer Zucker für einen neuen lexikalischen Bereich erstellt wird mit fn dann sofort Anwendung:

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

So könnte man let mit einem einfachen Makro implementieren und 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