Makro untuk melakukan apa yang Anda inginkan
Sebagai latihan sejenis:
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE."
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
Sekarang coba:
(setq-every "/foo/bar" f-loc1 f-loc2)
bagaimana cara kerjanya
Karena orang ingin tahu bagaimana cara kerjanya (menurut komentar), berikut adalah penjelasannya. Untuk benar-benar mempelajari cara menulis makro, pilih buku Common Lisp yang baik (ya, Common Lisp, Anda akan dapat melakukan hal yang sama di Emacs Lisp, tetapi Common Lisp sedikit lebih kuat dan memiliki buku yang lebih baik, IMHO).
Macro beroperasi pada kode mentah. Makro tidak mengevaluasi argumen mereka (tidak seperti fungsi). Jadi kita di sini tidak dievaluasi valuedan koleksi vars, yang untuk makro kita hanya simbol.
prognkelompok beberapa setqbentuk menjadi satu. Hal ini:
(mapcar (lambda (x) (list 'setq x value)) vars)
Hanya menghasilkan daftar setqformulir, menggunakan contoh OP itu akan menjadi:
((setq f-loc1 "/foo/bar") (setq f-loc2 "/foo/bar"))
Anda lihat, formulir itu di dalam formulir backquote dan diawali dengan koma
,. Di dalam formulir backquoted semuanya dikutip seperti biasa, tetapi ,
evaluasi " mapcarnyalakan " sementara, sehingga keseluruhan dievaluasi pada waktu ekspansi makro.
Akhirnya @menghapus tanda kurung luar dari daftar dengan setqs, jadi kami mendapatkan:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Macro dapat mengubah kode sumber Anda secara sewenang-wenang, bukankah hebat?
Peringatan
Berikut ini adalah peringatan kecil, argumen pertama akan dievaluasi beberapa kali, karena makro ini pada dasarnya diperluas sebagai berikut:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Anda lihat, jika Anda memiliki variabel atau string di sini tidak apa-apa, tetapi jika Anda menulis sesuatu seperti ini:
(setq-every (my-function-with-side-effects) f-loc1 f-loc2)
Maka fungsi Anda akan dipanggil lebih dari sekali. Ini mungkin tidak diinginkan. Berikut ini cara memperbaikinya dengan bantuan once-only(tersedia dalam
paket MMT ):
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE.
VALUE is only evaluated once."
(mmt-once-only (value)
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars))))
Dan masalahnya hilang.