2009-03-08 5 views
34

Я хочу создать локальный экземпляр класса Java Scanner в программе clojure. Почему это не работает:let vs def in clojure

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

, но это позволит мне создать глобальный экземпляр так:

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

Я был под впечатлением, что единственная разница была сфера, но, по-видимому, нет. В чем разница между let и def?

ответ

48

Проблема заключается в том, что использование let неправильно.

Пусть работает так:

(let [identifier (expr)]) 

Так что ваш пример должен быть что-то вроде этого:

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

Вы можете использовать только лексические привязки, сделанные с арендой в пределах аренды (открытие и закрытие parens). Пусть просто создает набор лексических привязок. Я использую def для создания глобальной привязки и позволяет привязывать что-то, что я хочу, только в области let, поскольку он сохраняет чистоту. У обоих есть свои возможности.

ПРИМЕЧАНИЕ: (класс.) Является таким же, как (новый класс), это просто синтаксический сахар.

+0

+1 для последних строк. –

11

Правильный синтаксис:

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

Синтаксис для них различен, даже если значения связаны.

let принимает список привязок (пары значений по значению), а затем выражения для оценки в контексте этих привязок.

def просто берет одну привязку, а не список и добавляет ее в глобальный контекст.

28

LET не «делает лексическое привязку в текущей области действия», а «создает новую лексическую область со следующими связями».

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

Я вижу, что вроде как использование C# или Python с, но без каких-либо разрушений (это было бы как бы глупое неизменное состояние в любом случае). –

7

Упрощенная: Защиту для глобальных констант, пусть для локальных переменных.

+3

Нет, это упрощение, и именно это приводит к путанице первоначального искателя.LET создает _new_block_ с лексическими привязками, тогда как DEF только создает новую «глобальную» привязку. – Svante

+0

Звучит неправильно. Def всегда связывается с Var и, следовательно, не является константой. Связи пространств имен также могут быть изменены, поэтому они даже меньше константы. Пусть константа, она не может быть изменена или повторно привязана вообще. Поэтому, по крайней мере, я бы сказал: «def для глобальных переменных, пусть для локальных констант. –

0

Вы могли бы думать о let, как синтаксический сахаре для создания новой лексической области с fn затем применить его сразу:

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

Таким образом, вы могли бы реализовать let с простым макросом и 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