2012-02-07 10 views
5

Trong Clojure, bạn có thể hủy liên kết một danh sách các giá trị để tạo mã, ví dụ:Tại sao bạn không thể unquote-splice trong mã bình thường (unquoted)?

(def extra-values [1 2 3 4]) 

`(+ 100 200 [email protected]) 
=> (clojure.core/+ 100 200 1 2 3 4) 

Có vẻ hợp lý rằng cách tiếp cận tương tự sẽ hoạt động trong ngữ cảnh không được kiểm soát, ví dụ:

(def extra-values [1 2 3 4]) 

(+ 1000 [email protected]) 
=> [an error, but one could argue that the answer should be 1010??] 

Có bất kỳ kỹ thuật/lý do philosphical sâu tại sao điều này không thể làm việc?

+0

Có lẽ để tránh pha trộn của "Meta" tính năng của ngôn ngữ với tính năng "bình thường" cho ngôn ngữ :) – Ankur

Trả lời

13

Một lý do đơn giản là sau đó

`(+ 100 200 [email protected]) 

sẽ được xác định kém: nó mở rộng để

(+ 100 200 1 2 3 4) 

hoặc

(+ 100 200 [email protected]) 

? Cả hai đều là cách diễn giải hợp lệ nếu cấu trúc [email protected] là hợp pháp trong ngữ cảnh đó.

Nó cũng gây ra các vấn đề nghiêm trọng trong hệ thống macro. Hãy xem xét

(defmacro foo [x & args] 
    `(list ~x ~(count args))) 

(let [data '(1 2 3)] 
    (foo "three" [email protected])) 

Làm cách nào để có thể chuyển được thông tin? Nó chắc chắn không thể mở rộng mà tại thời gian biên dịch, do đó, bây giờ unquote-nối chỉ hợp lệ trong một số ngữ cảnh không được trích dẫn.

Và tổng thể nó chỉ làm lẫn lộn lên tiếng để phù hợp với sự thiếu hiểu biết của khái niệm cốt lõi - nếu bạn thực sự muốn unquote-nối để xây dựng một danh sách đối số phức tạp, bạn có thể dễ dàng sử dụng apply trong một cái gì đó giống như

(apply + `(100 [email protected] 200)) 
+0

Tốt câu trả lời, tôi thích ví dụ. Cảm ơn! – mikera

2

Điểm của syntax-quote, unquoteunquote-splicing là để giúp nhà phát triển viết macro.

Ví dụ, không syntax-quoteunquote bạn sẽ phải viết

user=> (list :a extra-values) 
(:a [1 2 3 4]) 

thay vì:

user=> `(:a ~extra-values) 
(:a [1 2 3 4]) 

Trong trường hợp trước đó là khó khăn hơn cho người đọc (đọc của con người - không phải là repl) để hiểu biểu mẫu kết quả sẽ trông như thế nào, trong khi trường hợp thứ hai duy trì 'hình dạng' của biểu mẫu kết quả.

Vì vậy, nếu thay vì vector[1 2 3 4], chúng tôi muốn ghép các nội dung của extra-values làm thành phần biểu mẫu kết quả?Chúng ta cần unquote-splicing để chúng ta có thể viết:

user=> `(+ 100 200 [email protected]) 
(clojure.core/+ 100 200 1 2 3 4) 

thay vì:

user=> (concat `(+ 100 200) extra-values) 
(clojure.core/+ 100 200 1 2 3 4) 

Một lần nữa phiên bản unquote-splicing cho phép mã để giống với các 'hình' của mẫu kết quả khi mã được đánh giá, trong khi trong phiên bản thứ hai, 'hình dạng' bị mất trong tiếng ồn của applylist.

Cả hai ví dụ này rất đơn giản, nhưng syntax-quote và bạn bè thực sự đến với riêng mình khi viết các macro phức tạp hơn.

Quay lại câu hỏi tại sao bạn không thể viết (+ 1000 [email protected])? Chúng tôi đã có mà chức năng trong apply (với một vài hạn chế hơn):

user=> (apply + 1000 extra-values) 
1010