İstediğinizi yapacak bir makro
Bir çeşit egzersiz olarak:
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE."
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
Şimdi deneyin:
(setq-every "/foo/bar" f-loc1 f-loc2)
O nasıl çalışır
İnsanlar nasıl çalıştığını merak ettiklerinden (yorumlara göre), işte bir açıklama. Makro yazmayı gerçekten iyi bir Common Lisp kitabı seçmeyi öğrenmek için (evet, Common Lisp, Emacs Lisp'de aynı şeyleri yapabileceksiniz, ancak Common Lisp biraz daha güçlü ve daha iyi kitapları var, IMHO).
Makrolar ham kod üzerinde çalışır. Makrolar argümanlarını değerlendirmez (işlevlerin aksine). Yani burada değerlendirilmedik value
ve koleksiyonumuz var vars
, ki bunlar bizim makrolarımız için sadece semboller.
progn
birkaç setq
formu bir grupta toplar . Bu şey:
(mapcar (lambda (x) (list 'setq x value)) vars)
Sadece setq
OP'nin örneğini kullanarak formların bir listesini oluşturur :
((setq f-loc1 "/foo/bar") (setq f-loc2 "/foo/bar"))
Gördüğünüz gibi, form backquote formunun içindedir ve bir virgül ile gelir
,
. Geri alıntılanan formun içinde her şey genellikle alıntılanır, ancak ,
geçici olarak “açık” değerlendirme yapılır, bu nedenle tamamı mapcar
makro genişleme zamanında değerlendirilir.
Son olarak @
dış parantezleri setq
s ile listeden kaldırır , böylece:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Makrolar kaynak kodunuzu keyfi olarak dönüştürebilir, harika değil mi?
Bir uyarı
İşte küçük bir uyarı, ilk argüman birkaç kez değerlendirilecek, çünkü bu makro esasen aşağıdakilere genişliyor:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Görüyorsunuz, eğer burada bir değişkeniniz veya dizeniz varsa sorun değil, fakat böyle bir şey yazarsanız:
(setq-every (my-function-with-side-effects) f-loc1 f-loc2)
Ardından işleviniz birden fazla kez çağrılır. Bu istenmeyen bir durum olabilir. Yardımı once-only
(
MMT paketinde bulunur ) yardımıyla nasıl düzelteceğiniz aşağıda açıklanmıştır :
(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))))
Ve sorun gitti.