deixe vs def em Clojure
Pergunta
Eu quero fazer uma instância local de uma classe Scanner
Java em um programa Clojure. Por que isso não funciona:
; gives me: count not supported on this type: Symbol
(let s (new Scanner "a b c"))
mas me permite criar uma instância global como este:
(def s (new Scanner "a b c"))
Eu estava sob a impressão de que a única diferença era escopo, mas aparentemente não. Qual é a diferença entre let
e def
?
Solução
O problema é que o uso do let
está errado.
Let funciona assim:
(let [identifier (expr)])
Portanto, o seu exemplo deve ser algo como isto:
(let [s (Scanner. "a b c")]
(exprs))
Você só pode usar as ligações lexicais feitas com let no âmbito da let (a abertura e parênteses de fechamento). Vamos apenas cria um conjunto de ligações lexicais. Eu uso def para fazer uma ligação global e permite a ligação de algo que eu quero apenas no âmbito do let como ele mantém as coisas limpas. Ambos têm seus usos.
NOTA: (Class.) É o mesmo que (nova Classe), é apenas açúcar sintático
.Outras dicas
LET não é "fazer uma ligação de lexical no escopo atual", mas "fazer um novo escopo lexical com as seguintes ligações".
(let [s (foo whatever)] ;; s is bound here ) ;; but not here
(def s (foo whatever)) ;; s is bound here
sintaxe correta:
(let [s (Scanner. "a b c")] ...)
simplificado:. def é para constantes globais, deixe é para variáveis ??locais
A sintaxe para eles é diferente, mesmo se os significados estão relacionados.
let leva um lista de ligações (valor pares nome) seguido por expressões para avaliar no contexto daqueles vinculativo.
def só tem uma ligação, não uma lista, e adiciona-lo para o contexto global.
Você poderia pensar em let
como açúcar sintático para a criação de um novo escopo lexical com fn
em seguida, aplicá-lo imediatamente:
(let [a 3 b 7] (* a b)) ; 21
; vs.
((fn [a b] (* a b)) 3 7) ; 21
Assim, você poderá implementar let
com uma macro simples e 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