2009-03-08 36 views
34

Tôi muốn tạo một phiên bản cục bộ của lớp Java Scanner trong chương trình clojure. Tại sao điều này không làm việc:let vs def in clojure

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

nhưng nó sẽ cho tôi tạo một đối tượng toàn cầu như thế này:

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

Tôi đã theo ấn tượng rằng sự khác biệt duy nhất là phạm vi, nhưng dường như không. Sự khác nhau giữa letdef là gì?

Trả lời

48

Vấn đề là việc bạn sử dụng let là sai.

Hãy làm việc như thế này:

(let [identifier (expr)]) 

Vì vậy, ví dụ bạn nên được một cái gì đó như thế này:

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

Bạn chỉ có thể sử dụng các ràng buộc từ vựng được thực hiện với let trong phạm vi let (khai mạc và đóng cửa parens). Hãy chỉ tạo ra một tập hợp các liên kết từ vựng. Tôi sử dụng def để tạo ra một ràng buộc toàn cầu và cho phép ràng buộc một cái gì đó tôi muốn chỉ trong phạm vi của let vì nó giữ mọi thứ sạch sẽ. Cả hai đều có cách sử dụng của họ.

LƯU Ý: (Lớp.) Giống như (Lớp mới), nó chỉ là cú pháp.

+0

1 cho dòng cuối cùng .. –

11

đúng cú pháp:

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

Cú pháp cho chúng khác nhau, ngay cả khi ý nghĩa có liên quan.

hãy để danh sách các ràng buộc (cặp giá trị tên) theo sau là biểu thức để đánh giá trong ngữ cảnh của các ràng buộc đó.

def chỉ mất một ràng buộc, không phải danh sách và thêm nó vào ngữ cảnh chung.

28

LET không phải là "thực hiện một liên kết từ vựng trong phạm vi hiện tại", nhưng "thực hiện một phạm vi từ vựng mới với các ràng buộc sau đây".

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

Tôi thấy, vì vậy loại như C# 's bằng cách sử dụng hoặc Python với nhưng không có bất kỳ sự phá hủy (mà sẽ là loại câm cho nhà nước bất biến anyway). –

7

Giản: def là hằng số toàn cầu, chúng ta hãy là cho các biến địa phương.

+3

Không, đó là một sự đơn giản hóa, và chính xác điều này dẫn đến sự nhầm lẫn của người hỏi ban đầu.LET tạo ra một _new_block_ với các ràng buộc từ vựng, trong khi DEF chỉ tạo một ràng buộc mới "toàn cục". – Svante

+0

Nghe có vẻ sai với tôi. Def luôn luôn liên kết với một Var, và do đó không phải là một hằng số. Các ràng buộc không gian tên cũng có thể được thay đổi, vì vậy chúng thậm chí còn ít hơn một hằng số. Để cho là một hằng số, nó không thể thay đổi hoặc được ràng buộc lại chút nào. Vì vậy, ít nhất tôi sẽ nói: "def là cho các biến toàn cục, hãy để cho các hằng số cục bộ. –

0

Bạn có thể nghĩ let như cú pháp đường cho việc tạo ra một phạm vi từ vựng mới với fn sau đó áp dụng nó ngay lập tức:

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

Vì vậy, bạn có thể thực hiện let với một macro đơn giản và 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