2010-10-04 40 views
14

Tôi chưa bao giờ nghĩ về điều này cho đến khi tôi giải thích một số mã clojure cho một đồng nghiệp không quen thuộc với clojure. Tôi đã giải thích let cho anh ta khi anh ta hỏi tại sao bạn sử dụng một vector để khai báo các ràng buộc chứ không phải là một danh sách. Tôi không thực sự có câu trả lời cho anh ta. Nhưng ngôn ngữ không hạn chế bạn sử dụng danh sách:Tại sao yêu cầu một véc tơ?

=> (let (x 1) x) 
java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:0) 

Tại sao chính xác là điều này?

+0

Tôi tưởng tượng nó hoàn toàn là dễ đọc, và để cho thi hành một véc tơ chỉ đơn giản là đảm bảo thành ngữ được giữ. – MayDaniel

+0

(Cần có vectơ theo nghĩa đen cho tất cả các macro "let" và "with-".) – MayDaniel

+1

Điều này giống như luật tự nhiên. Bạn có thể lý do * rằng * nó là như thế, nhưng không * tại sao *.Cho dù lý do thực sự cho quyết định này là dễ đọc, một số thực hiện Đề án, một quy ước hoặc loại bữa ăn sáng mà Rich đã có vào ngày đó vẫn còn trong bóng tối. Người duy nhất có thể trả lời câu hỏi này là Rich. Đối với Clojure chúng tôi đang ở một vị trí may mắn, cho vũ trụ .... – kotarak

Trả lời

25

Chủ yếu là khả năng đọc, tôi hình dung. Bất cứ khi nào các ràng buộc là cần thiết trong Clojure, một vectơ được sử dụng khá thường xuyên. Rất nhiều người đồng ý rằng các vectơ cho các ràng buộc làm cho mọi thứ trở nên tốt hơn, và làm cho nó dễ dàng hơn để phân biệt ràng buộc là gì và mã chạy là gì.

Just for fun:

user=> (defmacro list-let [bindings & body] `(let ~(vec bindings) [email protected])) 
#'user/list-let 
user=> (macroexpand-1 '(list-let (x 0) (println x))) 
(clojure.core/let [x 0] (println x)) 
user=> (list-let (x 0 y 1) (println x y)) 
0 1 
nil 
+4

Tôi bỏ phiếu cho câu trả lời này, vì nó đánh bại tôi bằng 2 phút ** VÀ ** có mã! Chương trinh hay! – fogus

+3

Đúng, Hickey đã đề cập đến lý do có thể đọc được trong cuộc nói chuyện đồng thời của anh ấy, tôi nghĩ vậy. –

+5

Sử dụng một vectơ đen cũng làm cho nó rõ ràng nó không phải là một cuộc gọi chức năng. list-let làm việc nhưng bạn phải biết rằng danh sách đầu tiên không được đánh giá bình thường. Một khi bạn có cú pháp vector theo nghĩa đen bạn cũng có thể tận dụng lợi thế của nó. –

11

Clojure đã rất cố gắng để phù hợp. Không có lý do kỹ thuật nào với biểu mẫu danh sách có thể không được sử dụng trong let, fn, with-open, v.v ... Thực tế, bạn có thể tự tạo riêng cho mình my-let. Tuy nhiên, ngoài việc nổi bật rõ ràng, vectơ được sử dụng nhất quán trên các hình thức có nghĩa là "đây là một số ràng buộc". Bạn nên cố gắng duy trì lý tưởng đó trong mã của riêng bạn.

13

Đây là một thành ngữ từ Đề án. Trong nhiều triển khai Đề án, dấu ngoặc vuông có thể được sử dụng thay thế cho nhau bằng dấu ngoặc tròn trong các danh sách chữ. Trong các triển khai Đề án đó, các dấu ngoặc vuông thường được sử dụng để phân biệt các danh sách tham số, các danh sách đối số và các ràng buộc từ các biểu thức S hoặc các danh sách dữ liệu.

Trong Clojure, dấu ngoặc đơn và dấu ngoặc đơn có nghĩa là những thứ khác nhau, nhưng chúng được sử dụng theo cách tương tự trong khai báo ràng buộc.

+0

+1: điều này nghe có vẻ giống như một 'lý do' để quy ước. – progo

1

tôi đoán là nó một quy ước

fn sử dụng nó, defn sử dụng nó, loop sử dụng.

có vẻ như nó dành cho mọi thứ giống như một khối mã có một số thông số; cụ thể hơn, các dấu ngoặc vuông là để đánh dấu các tham số đó

các hình thức khác cho các khối mã không sử dụng nó, như if hoặc do. họ không có bất kỳ tham số

1

Một cách khác để suy nghĩ về điều này là let chỉ đơn giản là bắt nguồn từ lambda. Hai biểu thức là tương đương:

((fn [y] (+ y 42)) 10) 
(let [y 10] (+ 42 y)) 

Vì vậy, như một điểm học tập hoặc giảng dạy, bạn có thể thậm chí viết phiên bản rất thô sơ của riêng bạn let rằng mất một danh sách cũng như một vector:

(defmacro my-let [x body] 
    (list (list `fn[(first x)] 
       `~body) 
     (last x))) 

(my-let (z 42) (* z z)) 

mặc dù sẽ không có lý do thực tế để làm điều này.

Các vấn đề liên quan