пусть против def в ближайшем будущем - PullRequest
36 голосов
/ 08 марта 2009

Я хочу создать локальный экземпляр класса Java Scanner в программе 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?

Ответы [ 6 ]

52 голосов
/ 08 марта 2009

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

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

(let [identifier (expr)])

Итак, ваш пример должен выглядеть примерно так:

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

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

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

33 голосов
/ 09 марта 2009

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

(let [s (foo whatever)]
  ;; s is bound here
  )
;; but not here
(def s (foo whatever))
;; s is bound here
12 голосов
/ 08 марта 2009

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

(let [s (Scanner. "a b c")] ...)
11 голосов
/ 11 марта 2009

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

4 голосов
/ 08 марта 2009

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

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

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

1 голос
/ 08 декабря 2013

Вы можете думать о 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 [~@(map first pairs)] ~@body) ~@(map last pairs)))
   (partition 2 bindings)))

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