Đây là một cái tôi sử dụng để gỡ lỗi (trong Clojure):
user=> (defmacro print-var [varname] `(println ~(name varname) "=" ~varname))
#'user/print-var
=> (def x (reduce * [1 2 3 4 5]))
#'user/x
=> (print-var x)
x = 120
nil
Tôi đã phải đối phó với một bảng băm cuộn bằng tay trong C ++, trong đó get
phương thức lấy tham chiếu chuỗi không phải là một đối số, nghĩa là tôi không thể gọi nó bằng một nghĩa đen. Để làm cho nó dễ đối phó hơn, tôi đã viết một cái gì đó như sau:
#define LET(name, value, body) \
do { \
string name(value); \
body; \
assert(name == value); \
} while (false)
Mặc dù vấn đề như thế này khó có thể xảy ra, nhưng tôi thấy thật tuyệt vời khi bạn có thể có các macro không đánh giá các đối số của chúng hai lần, ví dụ bằng cách đưa ra một ràng buộc thực sự . (Phải thừa nhận, ở đây tôi có thể có được xung quanh nó).
Tôi cũng dùng đến cách hack đồ đạc cực kỳ xấu xí do ... while (false)
để bạn có thể sử dụng nó trong phần sau của một và nếu vẫn có phần công việc khác như mong đợi. Bạn không cần điều này trong lisp, đó là chức năng của các macro hoạt động trên các cây cú pháp chứ không phải là chuỗi (hoặc chuỗi mã thông báo, tôi nghĩ, trong trường hợp của C và C ++) sau đó trải qua phân tích cú pháp.
Có một số macro phân luồng tích hợp có thể được sử dụng để sắp xếp lại mã của bạn sao cho nó đọc rõ ràng hơn ('phân luồng' như trong 'gieo mã của bạn', chứ không phải song song). Ví dụ:
(->> (range 6) (filter even?) (map inc) (reduce *))
Nó lấy biểu mẫu đầu tiên (range 6)
và biến nó thành đối số cuối cùng của biểu mẫu tiếp theo, (filter even?)
lần lượt được tạo thành đối số cuối cùng của biểu mẫu tiếp theo, v.v., như vậy, phần trên được viết lại thành
(reduce * (map inc (filter even? (range 6))))
Tôi nghĩ rằng người đầu tiên đọc rõ ràng hơn nhiều: "lấy những dữ liệu này, làm cái này với cái kia, rồi làm cái kia, rồi làm cái kia và chúng ta đã hoàn thành", nhưng đó là chủ quan; Một cái gì đó khách quan đúng là bạn đọc các thao tác trong chuỗi chúng được thực hiện (bỏ qua sự lười biếng).
Ngoài ra còn có một biến thể chèn biểu mẫu trước đó làm đối số đầu tiên (chứ không phải cuối cùng). Một trường hợp sử dụng là số học:
(-> 17 (- 2) (/ 3))
Đọc là "lấy 17, trừ 2 và chia cho 3".
Nói về số học, bạn có thể viết một macro không phân tích cú pháp ký hiệu, để bạn có thể nói ví dụ (infix (17 - 2) / 3)
và nó sẽ nhổ ra (/ (- 17 2) 3)
cái nào có nhược điểm là ít đọc và lợi thế là biểu thức không hợp lệ. Đó là phần ngôn ngữ DSL / dữ liệu.