Ne zaman makro kullanılır veya kullanılmaz [kapalı]


12

Programımda ne zaman makro kullanmalı veya kullanmamalıyım?

Bu sorunun ilham kaynağı @tarsius tarafından verilen bilgilendirici bir cevaptır . Birçoğunun başkalarını paylaşmak için harika deneyimleri olduğuna inanıyorum. Umarım bu soru Büyük Öznel Sorulardan biri olur ve Emacs programcılarına yardımcı olur.

Yanıtlar:


13

Temel kural

Sözdizimi için makrolar kullanın , ancak hiçbir zaman anlambilim için kullanmayın.

Bazı sözdizimsel şeker için bir makro kullanmak iyidir, ancak makronun kendisinde veya genişlemesinde olsun, makro gövdeye mantık koymak kötü bir fikirdir. Bunu yapmanız gerektiğini düşünüyorsanız, bunun yerine bir işlev ve sözdizimsel şeker için bir "tamamlayıcı makro" yazın. Basitçe söylemek gerekirse, eğer letmakronuzda bir tane varsa sorun arıyor demektir.

Neden?

Makroların çok fazla dezavantajı var:

  • Derleme zamanında genişlerler ve bu nedenle birden çok sürüm arasında ikili uyumluluğu sağlamak için dikkatlice yazılmalıdır . Örneğin, bir makronun genişletilmesinde kullanılan bir fonksiyonun veya değişkenin kaldırılması, bu makrosu kullanan tüm bağımlı paketlerin bayt kodunu bozacaktır. Başka bir deyişle, bir makro uygulamasını uyumsuz bir şekilde değiştirirseniz, tüm bağımlı paketlerin yeniden derlenmesi gerekir. Ve ikili uyumluluk her zaman açık değildir…
  • Sezgisel bir değerlendirme talimatı vermeye dikkat etmelisiniz . Bir formu çok sık ya da yanlış zamanda ya da yanlış yerde değerlendiren bir makro yazmak kolaydır ...
  • Bağlayıcı anlambilimine dikkat etmelisiniz : Makrolar, bağlanma bağlamlarını genişletme sitesinden devralır , bu da hangi sözlüksel değişkenlerin var olduğunu ve sözlüksel bağlamanın bile mevcut olup olmadığını önceden bilmediğiniz anlamına gelir. Bir makro her iki bağlayıcı semantikle de çalışmalıdır.
  • Bununla ilgili olarak, kapanış oluşturan makrolar yazarken dikkat etmelisiniz . Unutmayın, bağlamaları sözlüksel tanımdan değil, genişleme sitesinden alırsınız, bu yüzden sizi kapattığınız şey ve kapıyı nasıl oluşturduğunuz için dikkat edin (unutmayın, söz konusu bağlamanın genişleme sitesinde etkin olup olmadığını bilmiyorsunuz ve kapanışlarınız bile var).

1
Sözcüksel bağlamaya karşı makro genişleme ile ilgili notlar özellikle ilginçtir; teşekkürler lunaryorn. (
Yazdığım

6

Benim ve diğerlerinin Elisp kodunu okuma, hata ayıklama ve değiştirme deneyimimden, makrolardan mümkün olduğunca kaçınmanızı öneririm.

Makrolarla ilgili en belirgin şey argümanlarını değerlendirmemeleri. Bu, bir makroya sarılmış karmaşık bir ifadeniz varsa, makro tanımına bakmadığınız sürece değerlendirilip değerlendirilmeyeceği ve hangi bağlamda hiçbir fikrinizin olmadığı anlamına gelir. Kendi makronuzun tanımını bildiğiniz için (şu anda, muhtemelen birkaç yıl sonra değil), bu kendiniz için büyük bir şey olmayabilir.

Bu dezavantaj fonksiyonlar için geçerli değildir: tüm argümanlar fonksiyon çağrısından önce değerlendirilir. Bu, bilinmeyen bir hata ayıklama durumunda değerlendirme karmaşıklığını oluşturabileceğiniz anlamına gelir. Düzgün veri döndürdükleri ve küresel duruma dokunmadıklarını varsaydığınız sürece, sizin bilmediğiniz işlevlerin tanımlarını doğrudan atlayabilirsiniz.

Başka bir şekilde yeniden yazmak için makrolar dilin bir parçası haline gelir. Makroları bilinmeyen bir kod okuyorsanız, neredeyse bilmediğiniz bir dilde bir kod okuyorsunuz.

Yukarıdaki rezervasyonların istisnaları:

Standart makroları gibi push, pop, dolistsizin için gerçekten çok şey ve diğer programcıların bilinmektedir. Temel olarak dil spesifikasyonunun bir parçasıdır. Ancak kendi makronuzu standartlaştırmak neredeyse imkansız. Sadece yukarıdaki örnekler gibi basit ve kullanışlı bir şey bulmak zor değil, aynı zamanda her programcıyı öğrenmeye ikna etmek de daha zordur.

Ayrıca, gibi makrolar umursamıyorum save-selected-window: onlar devlet depolamak ve geri yükleme ve argümanlarını aynı şekilde değerlendirir progn. Oldukça basit, aslında kodu basitleştirir.

Tamam makrolarının başka bir örneği defhydraveya gibi şeyler olabilir use-package. Bu makrolar temel olarak kendi mini dillerine sahiptir. Ve ya ya basit verileri tedavi ediyorlar ya da gibi davranıyorlar progn. Ayrıca genellikle en üst düzeydedir, bu nedenle makro argümanlarının bağımlı olması için çağrı yığını üzerinde bir değişken yoktur, bu da onu daha basit hale getirir.

Kötü bir makro örneği, benim görüşüme göre, magit-section-actionve magit-section-caseMagit içinde. Birincisi zaten kaldırıldı, ancak ikincisi hala kaldı.


4

Açık sözlü olacağım: "sözdizimi için kullan, anlambilim için değil" ne anlama geliyor. Bu yüzden bu cevabın bir kısmı lunaryonun cevabı ile, diğer kısmı ise orijinal soruyu cevaplama girişimim olacak.

Programlamada "anlambilim" kelimesi kullanıldığında, dil yazarının dillerini yorumlamayı seçtiği yolu ifade eder. Bu, tipik olarak dilin dilbilgisi kurallarını, okuyucunun aşina olduğu varsayılan diğer bazı kurallara dönüştüren bir dizi formüle dayanır. Örneğin, Plotkin, Operasyonel Semanti'ye Yapısal Yaklaşım adlı kitabında soyut sözdiziminin neyi değerlendirdiğini açıklamak için mantıksal türev dili kullanır (bir programı çalıştırmak ne anlama gelir). Diğer bir deyişle, sözdizimi bir düzeyde programlama dilini oluşturan şeyse, o zaman bazı semantiğe sahip olmalıdır, aksi takdirde, bir ... programlama dili değildir.

Ancak, şimdilik resmi tanımları unutalım, sonuçta, niyeti anlamak önemlidir. Öyleyse, lunaryon, programa yeni bir anlam eklenmeyeceği zaman okuyucularını makro kullanmaya teşvik edecek gibi görünüyor, ama sadece bir tür kısaltma. Bana göre bu, makroların gerçekte nasıl kullanıldığına garip ve keskin bir tezat oluşturuyor. Aşağıda açıkça yeni anlamlar yaratan örnekler verilmiştir:

  1. defun ve dilin önemli bir parçası olan arkadaşlar, işlev çağrılarını tanımladığınız terimlerle açıklanamaz.

  2. setfişlevlerin nasıl çalıştığını açıklayan kurallar, bir ifadenin etkilerini tanımlamak için yetersizdir (setf (aref x y) z).

  3. with-output-to-stringayrıca makro içindeki kodun anlambilimini de değiştirir. Benzer şekilde with-current-bufferve bir grup diğer with-makrolar.

  4. dotimes ve benzeri fonksiyonlar açısından tarif edilemez.

  5. ignore-errors kaydırdığı kodun anlambilimini değiştirir.

  6. cl-libPaket, eieiopaket ve Emacs Lisp'de kullanılan neredeyse her yerde bulunan kütüphanelerde tanımlanmış bir sürü makro var, ancak fonksiyon formları farklı yorumlara sahip olabilir.

Yani, herhangi bir şey varsa, makrolar bir dile yeni anlambilim kazandırmak için kullanılan araçtır. Bunu yapmanın alternatif bir yolunu düşünemiyorum (en azından Emacs Lisp'te değil).


Ne zaman makro kullanmak olmaz:

  1. Yeni semantiklerle yeni bir yapı getirmediklerinde (yani işlev işi iyi yapar).

  2. Bu sadece bir tür kolaylık olduğunda (yani mvb, cl-multiple-value-bindsadece kısaltmak için genişleyen bir makro oluşturmak ).

  3. Hata işleme kod makro tarafından gizlenmesi çok beklediğimde (belirtildiği gibi makroları hata ayıklamak zordur).


Ne zaman güçlü fonksiyonları yerine makroları tercih ederim:

  1. Etki alanına özgü kavramlar işlev çağrıları tarafından gizlendiğinde. Örneğin, aynı contextargümanı art arda çağrılması gereken bir grup işleve geçirmesi gerekiyorsa, bunları contextargümanın gizlendiği bir makroya sarmayı tercih ederim .

  2. İşlev biçimindeki genel kod aşırı ayrıntılı olduğunda (Emacs Lisp'teki çıplak yineleme yapıları benim zevkime göre çok ayrıntılıdır ve gereksiz yere programcıyı düşük düzeyli uygulama ayrıntılarına maruz bırakır).


örnekleme

Aşağıda, bilgisayar bilimlerinde anlambilim ile neyin kastedildiğine dair bir sezgi vermek için tasarlanmış sulandırılmış versiyon bulunmaktadır.

Yalnızca bu sözdizimi kurallarıyla son derece basit bir programlama diliniz olduğunu varsayalım:

variable := 1 | 0
operation := +
expression := variable | (expression operation expression)

Bu dille biz gibi "programları" inşa edebilir (1+0)+1ya da 0ya da ((0+0))vb

Fakat semantik kurallar sağlamadığımız sürece, bu "programlar" anlamsızdır.

Şimdi dilimizi (anlamsal) kurallarla donattığımızı varsayalım:

0+0  0+1  1+0  1+1  (exp)
---, ---, ---, ---, -----
 0   1+0   1    0    exp

Şimdi bu dili kullanarak hesaplayabiliriz. Yani, sözdizimsel temsili alabilir, soyut olarak anlayabiliriz (başka bir deyişle, soyut sözdizimine dönüşebilir), sonra bu temsili manipüle etmek için anlamsal kuralları kullanabiliriz.

Lisp dil ​​ailesi hakkında konuştuğumuzda, işlev değerlendirmenin temel semantik kuralları kabaca lambda-hesabıdır:

(f x)  (lambda x y)   x
-----, ------------, ---
 fx        ^x.y       x

Alıntı ve makro genişletme mekanizmaları meta-programlama araçları olarak da bilinir, yani sadece programlama yerine program hakkında konuşmaya izin verirler . Bunu "meta katmanı" kullanarak yeni anlambilim oluşturarak başarırlar. Böyle basit bir makro örneği:

(a . b)
-------
(cons a b)

Bu aslında Emacs Lisp'de bir makro değil, olabilirdi. Ben sadece basitlik uğruna seçtim. En yakın adayın bir işlev olarak (f x)yorumladığı , ancak mutlaka bir işlev olmadığı için f, yukarıda tanımlanan anlamsal kuralların hiçbirinin bu durum için geçerli olmayacağına dikkat edin a.


1
"Sözdizimsel şeker" aslında bilgisayar biliminde bir terim değildir. Mühendisler tarafından çeşitli şeyler ifade etmek için kullanılan bir şey. Yani kesin bir cevabım yok. Anlambilim hakkında konuştuğumuzdan, formun sözdizimini yorumlama kuralı: (x y)kabaca "y'yi değerlendirin, sonra x'i önceki değerlendirmenin sonucu ile arayın" dır. Yazdığınızda (defun x y), y değerlendirilmez ve ikisi de x değildir. Farklı semantikler kullanarak eşdeğer efektli bir kod yazıp yazamayacağınız, kendi semantiğine sahip bu kod parçasını reddetmez.
wvxvw

1
İkinci yorumunuz: Lütfen beni kullandığınız makronun tanımını söyleyen tanımına başvurabilir misiniz? Size yeni bir semantik kuralın makro aracılığıyla getirildiği bir örnek verdim. En azından kesin anlamda. Tanımları tartışmanın verimli olduğunu düşünmüyorum ve aynı zamanda CS'de kullanılan tanımların bu tartışma için en iyi eşleşme olduğunu düşünüyorum.
wvxvw

1
Şey ... "anlambilim" kelimesinin ne anlama geldiğine dair kendi fikriniz var, bu da biraz ironik, eğer düşünürseniz :) Ama gerçekten, bu şeylerin çok kesin tanımları var, sadece, iyi .. onları görmezden gel. Cevapta bağladığım kitap, CS karşılık gelen derste öğretildiği gibi anlambilim üzerine standart bir ders kitabı. Wiki'nin ilgili makalesini yeni okuduysanız: en.wikipedia.org/wiki/Semantics_%28computer_science%29 bunun ne hakkında olduğunu göreceksiniz. Örnek, (defun x y)işlev uygulamasına karşı yorumlama kuralıdır .
wvxvw

Ah, bunun bir tartışma şeklim olduğunu düşünmüyorum. Hatta denemek ve başlatmak için bir hataydı; Bunların hiçbir anlamı olmadığı için yorumlarımı kaldırdım. Zamanını boşa harcadığım için üzgünüm.
lunaryorn
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.