Saya ingin menunjukkan kurangnya pengetahuan saya dengan contoh.
Menggunakan dua definisi makro berikut,
(defmacro for (var from init to final do &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
(let ((tempvar 'max))
`(let ((,var ,init)
(,tempvar ,final))
(while (<= ,var ,tempvar)
,@body
(setq ,var (1+ ,var))))))
(defmacro for (var from init to final do &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
(let ((tempvar (make-symbol "max")))
`(let ((,var ,init)
(,tempvar ,final))
(while (<= ,var ,tempvar)
,@body
(setq ,var (1+ ,var))))))
makro pertama bayangan variabel apa pun nama max
yang mungkin terjadi di tubuh dan yang kedua tidak, yang dapat ditunjukkan dengan contoh berikut:
(let ((max 0)) ;; this variable is shadowed if the first macro defintion is used
(for i from 1 to 3 do
(setq square (* i i))
(if (> square max)
(princ (format "\n%d %d" i square)))))
Sejauh yang telah saya pelajari, evaluasi panggilan makro berfungsi seperti ini:
Makro dievaluasi dua kali. Pertama tubuh dievaluasi dan mengembalikan formulir. Formulir ini kemudian dievaluasi kembali.
Sejauh ini bagus.
Tetapi jika saya berasumsi bahwa makro benar-benar mengembalikan sepotong teks yang kebetulan merupakan bentuk lisp, yang kemudian ditafsirkan, saya mendapatkan konflik yang membuat saya tidak dapat memahami contoh di atas.
Apa potongan teks yang makro kedua yang menggunakan make-symbol
kembali, sehingga tidak ada bayangan yang terjadi? Dalam pemahaman saya, nama simbol yang dipilih acak ekstrim yang tidak masuk akal akan masuk akal.
Jika saya menggunakan pp-macroexpand...
kedua makro mengembalikan ekspansi yang sama.
Apakah seseorang dapat membantu saya keluar dari kebingungan ini?
sumber
print-gensym
danprint-circle
untukt
Anda akan dapat melihat perbedaan dalam ekspansi makro.#:max
. Apa artinya ? Saya sangat tertarik dengan detail lebih lanjut.#:
hanyalah sebuah konvensi dari printer untuk menunjukkan simbol uninterned (ini adalah apa yangprint-gensym
menyala), ada lebih detail dalam manual:(elisp) Creating Symbols
.Jawaban:
Seperti disebutkan dalam komentar, Anda harus mengaktifkan pengaturan ini untuk melihat bagaimana ekspansi makro bekerja lebih tepat. Perhatikan bahwa ini hanya mengubah cara
macroexpand
ditampilkan, makro masih berfungsi sama dalam kedua kasus:Kemudian instance pertama diperluas ke (salah):
Dan yang kedua berkembang menjadi (benar):
Untuk lebih memahami perbedaannya, pertimbangkan untuk mengevaluasi ini:
Seperti yang Anda lihat, hasil
(make-symbol "max")
tidak memiliki nilai. Ini memastikan kebenaran dari eval pass pertama pada makro. Dengan eval pass kedua,#:max
dapatkan nilai karena sekarang terikat sebagai variabel dinamis.sumber
print-circle
kalau tidak Anda punya 2#:max
yang tidakeq
(pertimbangkan juga bersarangfor
).cl-gensym
apakah masih belum jelas.