Muhalif bir fikir: Lisp'in eşcinselliği, Lisp hayranlarının inanacağından çok daha az faydalı bir şey.
Sözdizimsel makroları anlamak için derleyicileri anlamak önemlidir. Bir derleyicinin görevi, okunabilir kodu çalıştırılabilir koda dönüştürmektir. Çok yüksek bir perspektiften bakıldığında, bunun iki genel aşaması vardır: ayrıştırma ve kod oluşturma .
Ayrıştırma , kodu okuma, onu bir takım resmi kurallara göre yorumlama ve genellikle AST (Özet Sözdizimi Ağacı) olarak bilinen bir ağaç yapısına dönüştürme işlemidir. Programlama dilleri arasındaki tüm çeşitlilik için, bu dikkate değer bir ortaktır: temelde her genel amaçlı programlama dili bir ağaç yapısına ayrıştırılır.
Kod oluşturma , ayrıştırıcının AST'sini girdisi olarak alır ve resmi kuralların uygulanması yoluyla çalıştırılabilir koda dönüştürür. Performans açısından bakıldığında, bu çok daha basit bir iştir; birçok üst seviye dil derleyicisi zamanlarının% 75'ini veya daha fazlasını ayrıştırmaya harcıyor.
Lisp hakkında hatırlanması gereken şey , çok çok eski olması.. Programlama dilleri arasında sadece FORTRAN Lisp'ten daha eskidir. Geçmişe dönersek, ayrıştırma (derlemenin yavaş kısmı) karanlık ve gizemli bir sanat olarak kabul edildi. John McCarthy'nin Lisp teorisi hakkındaki orijinal makaleleri (gerçek bir bilgisayar programlama dili olarak asla gerçekleşmediğini düşünen bir fikir olmasına rağmen), her şey için her yerde modern S ifadelerinden biraz daha karmaşık ve anlamlı bir sözdizimi açıklar. "gösterimde. Bu daha sonra, insanlar gerçekten uygulamaya çalıştığında ortaya çıktı. O zamanlar ayrıştırma işlemi o kadar iyi anlaşılmadığı için, temelde üstüne düştüler ve ayrıştırıcıyı tamamen önemsiz hale getirmek için sözdizimini homoikonik bir ağaç yapısına bıraktılar. Sonuç, sizin (geliştiricinin) ayrıştırıcının çoğunu yapmanız gerektiğidir. Bunun için resmi AST'yi doğrudan kodunuza yazarak çalışın. Homoconicity, diğer her şeyi bu kadar zorlaştıracak kadar "makroları bu kadar kolaylaştırmaz"!
Bununla ilgili sorun, özellikle dinamik yazı yazarken, S ifadelerinin etraflarında çok fazla anlamsal bilgi taşıması çok zor. Tüm sözdiziminiz aynı tür bir şey olduğunda (liste listeleri), sözdizimi tarafından sağlanan bağlam biçiminde pek bir şey yoktur ve bu yüzden makro sistemin çalışacağı çok az şey vardır.
Derleyici teorisi, Lisp'in icat edildiği 1960'lı yıllardan bu yana uzun bir yol kat etti ve başardığı şeyler onun günü için etkileyici olsa da, şimdi oldukça ilkel görünüyorlar. Modern bir metaprogramlama sistemi örneği için (ne yazık ki takdir edilmeyen) Boo diline bir bakın. Boo, statik olarak yazılır, nesne yönelimli ve açık kaynaktır, böylece her AST düğümü, bir makro geliştiricinin kodu okuyabileceği iyi tanımlanmış bir yapıya sahip bir türe sahiptir. Dil, Python'dan esinlenilmiş basit bir sözdizimine sahiptir, bunlardan oluşturulan ağaç yapılarına anlamsal anlam kazandıran çeşitli anahtar kelimeler içerir ve metaprogramlaması, yeni AST düğümlerinin oluşturulmasını kolaylaştırmak için sezgisel bir quasiquote sözdizimine sahiptir.
İşte ben çağırır GUI kodu içinde farklı yerlerde bir grup aynı deseni uygulayarak anlayınca dün oluşturulan bir makro ben var BeginUpdate()
bir UI denetimi, bir de bir güncelleme gerçekleştirmek try
bloğu ve sonra çağrı EndUpdate()
:
macro UIUpdate(value as Expression):
return [|
$value.BeginUpdate()
try:
$(UIUpdate.Body)
ensure:
$value.EndUpdate()
|]
macro
Komut, aslında, bir makro kendisi , girdi olarak bir makro gövde alır ve makro işlemek için bir sınıfı oluşturur biri. Makro adını MacroStatement
temsil eden AST düğümü için duran bir değişken olarak makro adını kullanır . [| ... |] bir quasiquote bloğudur, quasiquote bloğunun içindeki ve içindeki koda karşılık gelen AST'yi oluşturur, $ sembolü belirtildiği gibi bir düğümde yer alan "unquote" özelliğini sağlar.
Bununla yazmak mümkündür:
UIUpdate myComboBox:
LoadDataInto(myComboBox)
myComboBox.SelectedIndex = 0
ve genişletmek için:
myComboBox.BeginUpdate()
try:
LoadDataInto(myComboBox)
myComboBox.SelectedIndex = 0
ensure:
myComboBox.EndUpdate()
Makroyu bu şekilde ifade etmek, bir Lisp makrosunda olduğundan daha basit ve sezgiseldir, çünkü geliştirici yapının ve özelliklerin MacroStatement
nasıl çalıştığını Arguments
ve nasıl çalıştığını bilir Body
ve içsel bilginin çok sezgisel olanları ifade eden kavramları ifade etmek için kullanılabileceğini bilir. yol. Aynı zamanda daha güvenlidir, çünkü derleyici yapısını bilir ve bir MacroStatement
şey için geçerli olmayan bir şeyi kodlamaya çalışırsanız MacroStatement
, derleyici derhal yakalayacaktır ve sizi havaya uçuruncaya kadar bilmemek yerine hatayı rapor edecektir. Çalışma zamanı.
Makroları Haskell, Python, Java, Scala vb. Üzerine aşılamak zor değildir, çünkü bu diller homoikon değildir; bu zor çünkü diller onlar için tasarlanmamış ve dilinizin AST hiyerarşisi bir makro sistem tarafından incelenmek ve manipüle edilmek üzere sıfırdan tasarlandığında en iyi şekilde çalışıyor. Baştan beri metaprogramming ile tasarlanmış bir dille çalışırken, makrolar üzerinde çalışmak çok daha basit ve daha kolaydır!