Terkadang saya perlu menetapkan nilai yang sama ke beberapa variabel.
Dengan Python, saya bisa melakukannya
f_loc1 = f_loc2 = "/foo/bar"
Tetapi di Elisp, saya menulis
(setq f_loc1 "/foo/bar" f_loc2 "/foo/bar")
Saya bertanya-tanya apakah ada cara untuk mencapai ini menggunakan "/foo/bar"
hanya sekali?
source
&target
ke jalur yang sama di awal dan saya mungkin berubahtarget
nanti, bagaimana mengaturnya?Jawaban:
setq
mengembalikan nilai, sehingga Anda bisa:Jika Anda tidak ingin mengandalkan itu, gunakan:
Secara pribadi saya akan menghindari yang terakhir dan bukannya menulis:
atau bahkan
Dan pendekatan pertama yang hanya akan saya gunakan dalam situasi yang agak khusus di mana sebenarnya menekankan niat, atau ketika alternatifnya adalah menggunakan pendekatan kedua atau yang lain
progn
.Anda dapat berhenti membaca di sini jika hal di atas membuat Anda bahagia. Tapi saya pikir ini adalah kesempatan baik untuk memperingatkan Anda dan orang lain untuk tidak menyalahgunakan makro.
Akhirnya, sementara tergoda untuk menulis makro seperti
setq-every
"karena ini adalah lisp dan kita bisa", saya akan sangat menyarankan untuk tidak melakukannya. Anda mendapatkan sangat sedikit dengan melakukannya:Tetapi pada saat yang sama Anda mempersulit pembaca lain untuk membaca kode dan memastikan apa yang terjadi.
setq-every
dapat diimplementasikan dengan berbagai cara dan pengguna lain (termasuk masa depan Anda) tidak dapat mengetahui mana yang penulis pilih, hanya dengan melihat kode yang menggunakannya. [Saya awalnya membuat beberapa contoh di sini tapi itu dianggap sarkastik dan kata-kata kasar oleh seseorang.]Anda dapat menangani overhead mental itu setiap kali Anda melihatnya
setq-every
atau Anda bisa hidup dengan satu karakter tambahan. (Setidaknya dalam kasus di mana Anda harus menetapkan hanya dua variabel, tetapi saya tidak ingat bahwa saya harus mengatur lebih dari dua variabel ke nilai yang sama sekaligus. Jika Anda harus melakukan itu, maka mungkin ada sesuatu yang salah dengan kode Anda.)Di sisi lain jika Anda benar-benar akan menggunakan makro ini lebih dari mungkin setengah lusin kali, maka tipuan tambahan mungkin sepadan. Misalnya saya menggunakan macro seperti
--when-let
daridash.el
perpustakaan. Itu memang membuat lebih sulit bagi mereka yang pertama kali menemukannya dalam kode saya, tetapi mengatasi kesulitan dalam memahami itu sepadan karena digunakan lebih dari hanya beberapa kali dan, setidaknya menurut saya, itu membuat kode lebih mudah dibaca .Orang bisa berpendapat bahwa hal yang sama berlaku untuk
setq-every
, tetapi saya pikir sangat tidak mungkin bahwa makro khusus ini akan digunakan lebih dari beberapa kali. Aturan praktis yang baik adalah bahwa ketika definisi makro (termasuk doc-string) menambahkan lebih banyak kode daripada penggunaan penghapusan makro, maka makro sangat mungkin berlebihan (kebalikannya belum tentu benar meskipun).sumber
setq
Anda dapat referensi itu nilai baru, sehingga Anda dapat menggunakan monstrositas ini juga:(setq a 10 b a c a d a e a)
yang menetapkan abcd dan e ke 10.Makro untuk melakukan apa yang Anda inginkan
Sebagai latihan sejenis:
Sekarang coba:
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
value
dan koleksivars
, yang untuk makro kita hanya simbol.progn
kelompok beberapasetq
bentuk menjadi satu. Hal ini:Hanya menghasilkan daftar
setq
formulir, menggunakan contoh OP itu akan menjadi:Anda lihat, formulir itu di dalam formulir backquote dan diawali dengan koma
,
. Di dalam formulir backquoted semuanya dikutip seperti biasa, tetapi,
evaluasi "mapcar
nyalakan " sementara, sehingga keseluruhan dievaluasi pada waktu ekspansi makro.Akhirnya
@
menghapus tanda kurung luar dari daftar dengansetq
s, jadi kami mendapatkan: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:
Anda lihat, jika Anda memiliki variabel atau string di sini tidak apa-apa, tetapi jika Anda menulis sesuatu seperti ini:
Maka fungsi Anda akan dipanggil lebih dari sekali. Ini mungkin tidak diinginkan. Berikut ini cara memperbaikinya dengan bantuan
once-only
(tersedia dalam paket MMT ):Dan masalahnya hilang.
sumber
value
pada waktu ekspansi makro.(macroexpand '(setq-every user-emacs-directory f-loc1 f-loc2))
->(progn (setq f-loc1 user-emacs-directory) (setq f-loc2 user-emacs-directory))
. Jikavalue
dievaluasi pada waktu ekspansi makro itu akan diganti dengan string yang sebenarnya. Anda dapat menempatkan panggilan fungsi dengan efek samping, sebagai gantinyavalue
, itu tidak akan dievaluasi sampai kode diperluas dijalankan, cobalah.value
sebagai argumen makro tidak dievaluasi secara otomatis. Masalah sebenarnya adalah bahwavalue
akan dievaluasi beberapa kali, yang mungkin tidak diinginkan,once-only
dapat membantu di sini.mmt-once-only
(yang membutuhkan dep eksternal), Anda bisa menggunakanmacroexp-let2
.set
, bukan untuk membungkussetq
makro. Atau cukup gunakansetq
dengan beberapa argumen, termasuk pengulangan argumen.Karena Anda dapat menggunakan dan memanipulasi simbol dalam lisp, Anda bisa dengan mudah mengulang daftar simbol dan menggunakannya
set
.sumber