Tôi không thể hiểu sự khác biệt giữa macroexpand và macroexpand-1.Sự khác biệt giữa macroexpand và macroexpand-1 trong Clojure
Bạn có thể cung cấp ví dụ không?
Tôi không thể hiểu sự khác biệt giữa macroexpand và macroexpand-1.Sự khác biệt giữa macroexpand và macroexpand-1 trong Clojure
Bạn có thể cung cấp ví dụ không?
Hãy nói rằng chúng ta có đoạn mã sau:
(defmacro inner-macro [arg]
`(println ~arg))
(defmacro top-level-macro [arg]
`(inner-macro ~arg))
(defn not-a-macro [] nil)
Sau đó, doc của macroexpand-1
nói:
Nếu hình thức đại diện cho một hình thức vĩ mô, trả lại sự bành trướng của nó, khác trả về hình thức.
Trên thực tế, nó:
user> (macroexpand-1 '(inner-macro "hello"))
(clojure.core/println "hello")
user> (macroexpand-1 '(top-level-macro "hello"))
(user/inner-macro "hello")
user> (macroexpand-1 '(not-a-macro))
(not-a-macro)
Nói cách khác, macroexpand-1
không chỉ là một bước của macroexpansion nếu hình thức cung cấp là một hình thức vĩ mô.
Sau đó, doc của macroexpand
:
Liên tiếp gọi macroexpand-1 vào mẫu cho đến khi nó không còn đại diện cho một hình thức vĩ mô, sau đó trả về nó.
Ví dụ:
user> (macroexpand '(top-level-macro "hello"))
(clojure.core/println "hello")
gì đã xảy ra? Ngay sau khi, (top-level-macro "hello")
mở rộng thành (user/inner-macro "hello")
, dưới dạng macro, macroexpand
sẽ thực hiện mở rộng lại một lần nữa. Kết quả của việc mở rộng thứ hai là (clojure.core/println "hello")
. Nó không phải là một hình thức vĩ mô, vì vậy macroexpand
chỉ trả về nó.
Vì vậy, chỉ để diễn đạt lại doc, macroexpand
sẽ đệ quy làm mở rộng cho đến khi cấp cao nhất hình thức không phải là một hình thức vĩ mô.
Cũng có thêm lưu ý trong doc macroexpand
's:
Lưu ý không macroexpand-1 cũng không macroexpand mở rộng macro trong subforms.
Điều đó có nghĩa là gì? Hãy nói rằng chúng tôi có một vĩ mô hơn:
(defmacro subform-macro [arg]
`(do
(inner-macro ~arg)))
Hãy thử để mở rộng nó:
user> (macroexpand-1 '(subform-macro "hello"))
(do (user/inner-macro "hello"))
user> (macroexpand '(subform-macro "hello"))
(do (user/inner-macro "hello"))
Từ, (do ...)
hình thức không phải là một vĩ mô macroexpand-1
và macroexpand
chỉ trả lại và không có gì hơn. Đừng nghĩ rằng macroexpand
sẽ làm như sau:
user> (macroexpand '(subform-macro "hello"))
(do (clojure.core/println "hello"))
sự khác biệt này khá đơn giản. Đầu tiên của tất cả các nền: khi trình biên dịch nhìn thấy cuộc gọi macro nó cố gắng mở rộng nó theo định nghĩa của nó.Nếu mã, được tạo bởi macro này chứa các macro khác, chúng cũng được mở rộng bởi trình biên dịch, và cứ thế, cho đến khi mã kết quả hoàn toàn không có macro. Vì vậy, macroexpand-1
chỉ mở rộng macro trên cùng và hiển thị kết quả (không có vấn đề gì tạo ra một cuộc gọi macro khác), trong khi macroexpand
cố gắng làm theo đường dẫn của trình biên dịch (một phần, không mở rộng macro trong biểu mẫu con). clojure.walk/maxroexpand-all
).
nhỏ ví dụ:
user> (defmacro dummy [& body]
`(-> [email protected]))
#'user/dummy
vĩ mô ngớ ngẩn này tạo ra các cuộc gọi đến một vĩ mô (->
)
user> (macroexpand-1 '(dummy 1 (+ 1)))
(clojure.core/-> 1 (+ 1))
macroexpand-1
chỉ mở rộng dummy
, nhưng giữ ->
chưa giãn nở
user> (macroexpand '(dummy 1 (+ 1)))
(+ 1 1)
macroexpand
mở rộng dummy
và sau đó mở rộng ->