2012-08-14 31 views
23

Tôi đang tìm hiểu về macro Clojure và các ví dụ mã đôi khi sẽ có cấu trúc '~symbol hoặc luân phiên ~'symbol. Tôi biết rằng (quote' ngăn không cho một biểu mẫu được đánh giá và backquote bổ sung thêm tiêu chuẩn không gian tên và điều đó tạo ra một biểu mẫu được trích dẫn để được đánh giá. Câu hỏi của tôi là: tại sao nó hữu ích để dừng lại sau đó bắt đầu đánh giá? Tôi cũng giả định rằng ~'symbol'~symbol là khác nhau, nhưng làm thế nào?Mục đích của ~ 'hoặc' ~ trong Clojure là gì?

Trả lời

30

~'symbol được sử dụng để tạo ra một biểu tượng không đủ tiêu chuẩn. Các macro của Clojure nắm bắt không gian tên theo mặc định, do đó, một biểu tượng trong macro thường được giải quyết thành (your-namespace/symbol). Thành ngữ báo giá không được trích dẫn trực tiếp dẫn đến tên biểu tượng đơn giản, không đủ tiêu chuẩn - (symbol) - bằng cách đánh giá biểu tượng được trích dẫn. Từ The Joy Of Clojure:

(defmacro awhen [expr & body] 
    `(let [~'it ~expr] ; refer to the expression as "it" inside the body 
    (when ~'it 
     (do [email protected])))) 

(awhen [:a :b :c] (second it)) ; :b 

'~symbol có thể được sử dụng để chèn tên trong macro hoặc tương tự. Tại đây, symbol sẽ bị ràng buộc với một giá trị - let [symbol 'my-symbol]. Giá trị này sau đó được chèn vào mã mà macro tạo ra bằng cách đánh giá symbol.

(defmacro def-symbol-print [sym] 
    `(defn ~(symbol (str "print-" sym)) [] 
    (println '~sym))) ; print the symbol name passed to the macro 

(def-symbol-print foo) 
(print-foo) ; foo 
+0

:) Cảm ơn bạn, điều đó có ý nghĩa. – Alex

+0

vẫn còn một điểm mà vẫn chưa rõ ràng với tôi: '(unquote (quote user/foo))' kết quả trong 'foo' thay vì' user/foo', khi nào và như thế nào nó xảy ra rằng không gian tên bị tước đi? Làm thế nào là nó phù hợp với hành vi "bình thường" của 'unquote' mà đánh giá các hình thức sau đây? – skuro

+1

Ví dụ đầu tiên không hoạt động. Nó sẽ là '\' (để [~ 'it ~ expr] ... ' – Ming

4

~ là macro trình đọc cho hàm unquote. trong một danh sách trích dẫn nó gây ra một biểu tượng được đánh giá khá sau đó được sử dụng như một biểu tượng văn chương

user> (def unquoted 4) 
user>`(this is an ~unquoted list) 
(user/this user/is user/an 4 clojure.core/list) 
user> 

tất cả mọi thứ ngoại trừ các biểu tượng không thể viện chứng được sử dụng giống như một biểu tượng mà không thể viện chứng đã được giải quyết để giá trị của nó 4. đây là nhất thường được sử dụng trong các macro viết. Các repl cũng in không gian tên (người dùng) trước mặt của tên khi nó được in danh sách kết quả.

nhiều macro, về cơ bản chỉ là các mẫu được thiết kế để thực hiện một loạt các biến thể nhỏ về một thứ không thể thực hiện được trong một hàm. Trong ví dụ này, một macro mẫu định nghĩa một hàm bằng cách tạo ra một cuộc gọi đến def. cú pháp-quote với unquoting làm cho điều này dễ dàng hơn nhiều để đọc:

user> (defmacro def-map-reducer [name mapper reducer] 
     `(defn ~name [& args#] 
       (reduce ~reducer (map ~mapper args#)))) 

#'user/def-map-reducer 
user> (def-map-reducer add-incs inc +) 
#'user/add-incs 
user> (add-incs 1 2 3 4 5) 
20 

so với:

user> (defmacro def-map-reducer [name mapper reducer] 
      (let [args-name (gensym)] 
       (list `defn name [`& args-name] 
        (list `reduce reducer (list `map mapper args-name))))) 

#'user/def-map-reducer 
user> (def-map-reducer add-decs dec +) 
#'user/add-decs 
user> (add-decs 1 2 3 4 5) 
10 
user> 

trong ví dụ thứ hai tôi cũng không sử dụng tính năng tự động gensyms đặc trưng bởi vì tôi không ở cú pháp-trích dẫn

+0

Vì vậy, tôi biết tại sao tôi muốn sử dụng ~ trước biểu tượng trong danh sách mà trước đây tôi đã trích dẫn, câu hỏi của tôi là lý do tại sao tôi sử dụng ~ 'hoặc' ~ ngay bên cạnh nhau. – Alex

+0

hy vọng ví dụ này sẽ cho thấy động lực tốt hơn, nhờ phản hồi :) –

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