Câu trả lời được chứa trong câu hỏi: chỉ cần sử dụng gensym
như bạn sẽ làm nếu Clojure không có tự động-gensyms.
(defmacro make [v & body]
(let [value-sym (gensym)]
`(let [~value-sym ~(some-calc v)]
[email protected](replace {:value value-sym} body))))
Lưu ý rằng tôi không chắc chắn cho dù bạn thực sự muốn ~
hoặc [email protected]
ở đây - nó phụ thuộc nếu body
được coi là một chuỗi các biểu thức để thực hiện trong let
, hoặc một chuỗi các đối số cho hàm độc thân gọi điện. Nhưng [email protected]
sẽ trực quan hơn/bình thường hơn, vì vậy đó là những gì tôi sẽ đoán.
Cho dù macro này là ẩn dụ là một chút nghi ngờ: chắc chắn giới thiệu nv
vào phạm vi gọi là, nhưng về cơ bản không chủ ý nên tôi sẽ nói không. Trong phiên bản sửa đổi của tôi, chúng tôi không còn giới thiệu nv
hoặc bất kỳ thứ gì giống như nó, nhưng chúng tôi "kỳ diệu" thay thế :value
bằng v
. Tuy nhiên, chúng tôi chỉ làm điều đó ở cấp cao nhất của cơ thể, vì vậy nó không giống như giới thiệu một phạm vi thực sự - tôi muốn nói nó giống như làm cho mã của khách hàng bất ngờ phá vỡ trong các trường hợp góc.
Ví dụ về cách hành vi lừa đảo này có thể xuất hiện, hãy tưởng tượng rằng một trong các thành phần của body
là (inc :value)
. Nó sẽ không được thay thế bằng macro và sẽ mở rộng thành (inc :value)
, không bao giờ thành công. Vì vậy, thay vào đó, tôi khuyên bạn nên sử dụng macro ẩn dụ thực tế, giới thiệu một phạm vi thực sự cho một biểu tượng.Một cái gì đó như
(defmacro make [v & body]
`(let [~'the-value ~(some-calc v)]
[email protected]))
Và sau đó người gọi có thể chỉ cần sử dụng the-value
trong mã của họ, và nó hoạt động giống như một thực tế, thường xuyên ở địa phương ràng buộc: macro của bạn giới thiệu nó bằng ma thuật, nhưng nó không có bất kỳ thủ thuật đặc biệt khác .
Không chắc chắn nếu bạn có thể gọi nó là ẩn dụ: để được như vậy, 'nv' nên tham khảo một số phần của biểu mẫu yêu cầu macro. Nếu bạn tính ra 'some-calc' từ cơ thể macro thì bạn sẽ có một lời gọi ẩn dụ thích hợp hơn:' (make (some-calc x) (do-something-to nv)) 'trong đó' nv' chỉ đến ' (một số-calc x) '. Trong trường hợp của bạn, bạn sẽ có '(make x (do-some-thing-to nv))', nhưng sau đó 'nv' sẽ không trực tiếp tham chiếu đến bất cứ thứ gì trong biểu mẫu yêu cầu macro. – skuro
@skuro: Tôi hiểu, vì vậy về cơ bản đây là điều tồi tệ nhất của cả hai thế giới - giới thiệu một biểu tượng mới, tuy nhiên sẽ vẫn ẩn cho đến khi ai đó vô tình định nghĩa lại nó. Hf theo dõi lỗi đó :) May mắn thay, một 'gensym' rõ ràng theo đề xuất của amalloy giải quyết vấn đề này. –