Lisp benzeri sözdizimi genişletme mekanizmasıyla dilleri programlama [kapalı]


20

Lisp hakkında sınırlı bilgiye sahibim (boş zamanlarımda biraz öğrenmeye çalışıyorum) ama anladığım kadarıyla Lisp makroları Lisp'in kendisinde tanımlayarak yeni dil yapıları ve sözdizimi sunmaya izin veriyor. Bu, Lisp derleyicisini / yorumlayıcısını değiştirmeden kütüphane olarak yeni bir yapının eklenebileceği anlamına gelir.

Bu yaklaşım diğer programlama dillerinden çok farklıdır. Örneğin, Pascal'ı yeni bir döngü veya belirli bir deyimle genişletmek isteseydim, dilin sözdizimini ve anlambilimini genişletip derleyiciye bu yeni özelliği uygulamak zorunda kalacaktım.

Lisp ailesinin dışında, dili kendi içinde genişletmek için benzer bir olasılık sunan, diğer Lisp, Scheme, Clojure (?), Raket (?) Vb. Dışında) başka programlama dilleri var mı?

DÜZENLE

Lütfen uzun süren tartışmalardan kaçının ve cevaplarınızda açık olun. Bir şekilde veya başka bir şekilde genişletilebilen uzun bir programlama dilleri listesi yerine, bir uzatma mekanizması olarak Lisp makrolarına neyin özgü olduğunu ve hangi Lisp dışı programlama dillerinin bazı konsept sunduğunu kavramsal bir bakış açısıyla anlamak istiyorum. bu onlara yakın.


6
Lisp'in düzenli makroların yanı sıra başka bir numarası daha var. "Okuyucu Makroları" ayrıştırıcı sözdiziminin çalışma zamanında yakalanmasına ve genişletilmesine izin verir, böylece dilin temel simge yapısı bile kontrol altındadır.
ddyer

@ddyer: Teşekkürler, bunu bilmiyordum: okuma listeme eklenecek başka bir konu.
Giorgio

Bahse girerim Ruby meta programlaması bunu karşılayabilir.
Rig

1
Sorunuz çelişkilidir, önce bir liste istersiniz, sonra kavramsal bilgi istersiniz, hangisi ???

Bir liste istiyorum, ama genel bir değil (sadece bir şekilde genişletilebilir herhangi bir programlama dili değil) çünkü bu çok genel olurdu. Lisp'e benzer bir şekilde genişletilebilecek dilleri bilmek istiyorum (uzantı, bir tür meta dil değil, genişlettiği aynı dil kullanılarak tanımlanır). Péter Török, Thomas Eding, SK-logic ve Mechanical salyangozun cevapları aklımdakilere en yakın gibi görünüyor. Yine de tüm cevabı dikkatlice okumalıyım.
Giorgio

Yanıtlar:


19

Scala da bunu mümkün kılıyor (aslında yeni dil yapılarının tanımını ve hatta eksiksiz DSL'leri desteklemek için bilinçli olarak tasarlandı).

İşlevsel dillerde yaygın olan üst düzey işlevler, lambdalar ve köriler dışında, bunu mümkün kılan bazı özel dil özellikleri vardır *:

  • operatör yok - her şey bir işlevdir, ancak işlev adları '+', '-' veya ':' gibi özel karakterler içerebilir
  • noktalar ve parantezler tek parametreli yöntem çağrıları için atlanabilir, yani infix formuna a.and(b)eşdeğerdira and b
  • tek parametreli işlev çağrıları için normal parantez yerine kıvrımlı parantez kullanabilirsiniz - bu (köri ile birlikte) gibi şeyler yazmanıza izin verir

    val file = new File("example.txt")
    
    withPrintWriter(file) {
      writer => writer.println("this line is a function call parameter")
    }
    

    burada withPrintWriterher ikisi de tek bir parametre içeren iki parametre listesiyle düz bir yöntemdir

  • by-name parametreleri, lambdas'daki boş parametre listesini atlamanıza olanak tanır ve aramaları myAssert(() => x > 3)daha kısa bir formda olduğu gibi yazmanıza olanak tanır .myAssert(x > 3)

Bir örnek, DSL oluşturulması ayrıntılı olarak tartışılmıştır Scala Bölüm 11. Alan özgü Diller serbest kitabın Scala Programlama .

* Bunların Scala'ya özgü olduğunu kastetmiyorum, ama en azından çok yaygın görünmüyorlar. Yine de işlevsel dillerde uzman değilim.


1
+1: İlginç. Bu, sözdizimini genişletmek için yeni sınıflar tanımlayabileceğim ve bu yöntem imzalarının yeni sözdizimini bir yan ürün olarak sağlayacağı anlamına mı geliyor?
Giorgio

@Giorgio, temelde evet.
Péter Török

Bağlantılar artık çalışmıyor.
Nate Glenn

13

Perl, dilinin ön işlemesine izin verir. Bu genellikle dilde sözdizimini kökten değiştiren ölçüde kullanılmasa da, bazı tek modüllerde görülebilir:

Perl'in Python'da yazılmış gibi çalışmasına izin veren bir modül de var.

Perl içinde buna daha modern bir yaklaşım Filter :: Simple (perl5'teki çekirdek modüllerden biri) kullanmak olacaktır.

Tüm bu örneklerin "Perl'in Deli Doktoru" olarak anılan Damian Conway'i içerdiğini unutmayın. Perl içinde dilin nasıl istendiğini bükmek için hala inanılmaz güçlü bir yetenek.

Bu ve diğer alternatifler için perlfilter'da daha fazla dokümantasyon mevcuttur .


13

Haskell

Haskell'de "Şablon Haskell" ve "Quasiquotation" vardır:

http://www.haskell.org/haskellwiki/Template_Haskell

http://www.haskell.org/haskellwiki/Quasiquotation

Bu özellikler, kullanıcıların dilin sözdizimine normal yolların dışında önemli ölçüde eklemelerine olanak tanır. Bunlar derleme zamanında da çözülür, ki bence büyük bir zorunluluktur (en azından derlenmiş diller için) [1].

Haskell'de bir kez daha C benzeri bir dilde gelişmiş bir desen eşleştirici oluşturmak için kullandım:

moveSegment :: [Token] -> Maybe (SegPath, SegPath, [Token])
moveSegment [hc| HC_Move_Segment(@s, @s); | s1 s2 ts |] = Just (mkPath s1, mkPath s2, ts)
moveSegment _ = Nothing

[1] Aşağıdakiler sözdizimi uzantısı olarak nitelendirilir: runFeature "some complicated grammar enclosed in a string to be evaluated at runtime"ki bu elbette bir saçmalık yüküdür.


3
Haskell'in temel olarak özel sözdizimine izin veren, kendi operatörünüzü oluşturma veya lambda işlevleriyle birleştirilmiş otomatik körleme gibi diğer özellikleri de vardır (örneğin tipik kullanımını düşünün forM).
Xion

Dürüst olmak gerekirse, köri ve özel operatörlerin yeterli olmadığını düşünüyorum. Kişinin dili düzgün bir şekilde kullanmasına izin verir, ancak dile yeni / işlevsellik eklemenize izin vermez. TH ve QQ yapar. Sıkı bir anlamda, TH ve QQ, tam olarak yapmak için tasarlandıkları şeyi yapmaları anlamında da yapmazlar, ancak derleme zamanında gerçekten "dilden çıkmanıza" izin verirler.
Thomas Eding

1
"Ayrıca aşağıdakiler sözdizimi uzantısı olarak nitelendirilir ...": çok iyi bir nokta.
Giorgio

12

Tcl , genişletilebilir sözdizimini destekleme konusunda uzun bir geçmişe sahiptir. Örneğin, burada kardinaller, kareleri ve küpleri üzerinde üç değişkeni (durdurulana kadar) yineleyen bir döngü uygulaması:

proc loopCard23 {cardinalVar squareVar cubeVar body} {
    upvar 1 $cardinalVar cardinal $squareVar square $cubeVar cube

    # We borrow a 'for' loop for the implementation...
    for {set cardinal 0} true {incr cardinal} {
        set square [expr {$cardinal ** 2}]
        set cube [expr {$cardinal ** 3}]

        uplevel 1 $body
    }
}

Bu daha sonra şu şekilde kullanılır:

loopCard23 a b c {
    puts "got triplet: $a, $b, $c"
    if {$c > 400} {
        break
    }
}

Tekniğin bu tür Tcl programlamada yaygın kullanılır ve bunu yapmanın anahtarı sanely vardır upvarve uplevelkomutları ( upvarbağlandığı bir yerel değişkene başka kapsamda adlandırılmış değişken ve uplevelbaşka kapsam içinde komut dosyası çalıştıran: Her iki durumda da, 1gösterir söz konusu kapsam arayan kişidir). Ayrıca, GUI'ler için Tk'de (geri aramaların olaylara bağlanması için) vb.Veritabanlarıyla çiftleşen (sonuç kümesindeki her satır için bazı kodlar çalıştıran) kodda çok kullanılır.

Ancak, bu yapılanların sadece bir kısmı. Gömülü dilin Tcl olması bile gerekmez; neredeyse her şey olabilir (desteklerini dengelediği sürece - bu doğru değilse işler sözdizimsel olarak korkunç olur - ki bu programların büyük çoğunluğu) ve Tcl sadece gömülü yabancı dile gerektiği gibi gönderebilir. Bunu yapmanın örnekleri arasında Tcl komutlarını uygulamak için C gömme ve Fortran ile eşdeğerdir. (Muhtemelen, tüm Tcl'nin yerleşik komutları, bir anlamda, dilin kendisi değil, sadece standart bir kütüphane oldukları için bu şekilde yapılır.)


10

Bu kısmen anlambilim meselesidir. Lisp'in temel fikri, programın kendisi manipüle edilebilecek veriler olmasıdır. Lisp ailesinde, Scheme gibi yaygın olarak kullanılan diller , ayrıştırıcı anlamda yeni sözdizimi eklemenize gerçekten izin vermez ; hepsi sadece alanla sınırlı parantez içine alınmış listeler. Temel sözdizimi çok az şey yaptığından, hemen hemen herhangi bir anlamsal yapı oluşturabilirsiniz. Scala (aşağıda tartışılmıştır) benzerdir: değişken adı kuralları o kadar liberaldir ki kolayca DSL'leri kolayca oluşturabilirsiniz (aynı temel sözdizimi kurallarında kalırken).

Bu diller, Perl filtreleri anlamında yeni sözdizimini tanımlamanıza izin vermese de, DSL'ler oluşturmak ve dil yapıları eklemek için kullanabileceğiniz yeterince esnek bir çekirdeğe sahiptir.

Önemli ortak özellik, dillerin maruz kaldığı özellikleri kullanarak yerleşik olanların yanı sıra çalışan dil yapılarını tanımlamanıza izin vermesidir. Bu özellik için destek derecesi değişir:

  • Birçok eski diller yerleşik İşletmesi gibi fonksiyonlar sin(), round()vb kendi uygulamak için herhangi bir şekilde olmadan.
  • C ++ sınırlı destek sağlar. Örneğin bazı Yerleşik atmalarını gibi anahtar kelimelerle ( static_cast<target_type>(input), dynamic_cast<>(), const_cast<>(), reinterpret_cast<>()) şablon işlevleri için Boost kullanımlarını kullanarak taklit edilebilir lexical_cast<>(), polymorphic_cast<>(), any_cast<>(), ....
  • Java Denetim yapıları (dahili etti for(;;){}, while(){}, if(){}else{}, do{}while(), synchronized(){}, strictfp{}) ve kendi tanımlamak izin vermez. Scala bunun yerine, uygun bir kontrol yapısı benzeri sözdizimi kullanarak işlevleri çağırmanıza izin veren soyut bir sözdizimini tanımlar ve kütüphaneler bunu yeni kontrol yapılarını (örneğin react{}, aktörler kütüphanesinde) etkili bir şekilde tanımlamak için kullanır .

Ayrıca, Mathematica'nın Notation paketindeki özel sözdizimi işlevselliğine de bakabilirsiniz . (Teknik olarak Lisp ailesindedir, ancak her zamanki Lisp genişletilebilirliğinin yanı sıra farklı genişletilebilirlik özelliklerine de sahiptir.)


2
Yanlış. Lisp yok aslında yeni bir sözdizimi kesinlikle her türlü eklemenize olanak tanır. Bu örnekte olduğu gibi: meta-alternative.net/pfront.pdf - Lisp makrosundan başka bir şey değildir.
SK-logic

Bu, DSL'leri oluşturmak için özel olarak tasarlanmış bir dilde uygulanıyor gibi görünüyor . Tabii ki Lisp ailesinde de bu tür özellikler sağlayan bir dil yapabilirsiniz; Bu özelliğin, yaygın olarak kullanılan Lisps (örneğin Şema) tarafından desteklenen temel bir Lisp fikri olmadığı anlamına geliyordum. Açıklığa kavuşturmak için düzenlendi.
Mekanik salyangoz

Bu "DSL oluşturmak için kullanılan dil" oldukça tipik, minimalist bir Lisp üzerine inşa edilmiş bir makro koleksiyonudur. Diğer Lisp'lere kolayca taşınabilir (defmacro ...). Aslında şu anda sadece eğlence için bu dili Racket'e taşıyorum. Ancak, S-ifadeleri sözdizimi, olası yararlı semantiklerin çoğu için fazlasıyla yeterli olduğundan, bunun çok yararlı bir şey olmadığını kabul ediyorum.
SK-logic

Ve Scheme, resmi olarak R6RS'den başlayarak ve gayri resmi olarak çağlar için Common Lisp'den farklı değildir, çünkü (define-macro ...)içsel olarak her türlü ayrışmayı kullanabilen bir eşdeğer sağlar .
SK-logic

8

Rebol neredeyse tanımladığınız gibi görünüyor, ancak biraz yanlara doğru.

Belirli bir sözdizimini tanımlamak yerine, Rebol'daki her şey bir işlev çağrısıdır - anahtar kelime yoktur. (Evet, yeniden tanımlayabilirsiniz ifve whilegerçekten arzu ediyorsanız). Örneğin, bu bir ifaçıklamadır:

if now/time < 12:00 [print "Morning"]

if2 bağımsız değişken alan bir işlevdir: bir koşul ve bir blok. Koşul doğruysa blok değerlendirilir. Çoğu dil gibi geliyor değil mi? Blok, bir veri yapısıdır, kodla sınırlı değildir - bu, örneğin bir blok bloğudur ve "kod verilerdir" in esnekliğine hızlı bir örnektir:

SomeArray: [ [foo "One"] [bar "Two"] [baz "Three"] ]
foreach action SomeArray [action/1: 'print] ; Change the data
if now/time < 12:00 SomeArray/2 ; Use the data as code - right now, if now/time < 12:00 [print "Two"]

Sözdizimi kurallarına bağlı kaldığınız sürece, bu dili genişletmek çoğunlukla yeni işlevleri tanımlamaktan başka bir şey değildir. Bazı kullanıcılar, örneğin Rebol 3'ün özelliklerini Rebol 2'ye destekliyor.


7

Ruby'nin oldukça esnek bir sözdizimi var, bence bu "dili kendi içinde genişletme" yoludur.

Bir örnek tırmıktır . Ruby'de yazılmıştır, Ruby'dir, ama marka gibi görünür .

Bazı olasılıkları kontrol etmek için Ruby ve metaprogramming anahtar sözcüklerini arayabilirsiniz .


13
"esnek sözdizimi", "genişletilebilir sözdiziminden" ÇOK farklıdır. Ruby'de programladığımdan bu yana uzun zaman geçti, ancak Rake sadece iyi tasarlanmış yerleşik sözdizimi kullanımı gibi görünüyor. Başka bir deyişle, bu bir örnek değildir.
Thomas Eding

2
Bu bir derece meselesi değil, kibar değil mi? Sözdiziminin bazı yönlerini genişletebilen ancak diğerlerini genişletemeyen bir "genişletilebilir sözdizimi" dili ile bir "esnek sözdizimi" dili arasında nasıl ayrım yaparsınız?
comingstorm

1
Çizgi bulanıksa, çizgiyi geri itelim, böylece C genişletilebilir sözdizimini destekliyor.
Thomas Eding

Örneğinizle bağlantı kurmak için, çizgiyi buraya çizerim: Genişletilebilir sözdizimine sahip bir dil, make gibi görünen tırmık yapabilir. Esnek sözdizimi olan bir dil, makefiles derlemek ve çalıştırmak için genişletilebilir (ha, güzel dilsel harmanlama). Derecesi ile ilgili noktanız iyi. Belki bazı diller Make'i derlemeye izin verir, ancak Python'a izin vermez. Ve diğerleri her ikisine de izin verecekti.
Clayton Stanley

Make dosyalarını işlemek için herhangi bir turing tam dili yapılmalıdır. Sözdiziminin esnekliği, ne kadar zor olabileceğinin ötesinde bir faktör değildir.
Rig

7

Sözdizimini bahsettiğiniz şekilde genişletmek, alana özgü diller oluşturmanıza olanak tanır . Sorunuzu yeniden ifade etmenin belki de en yararlı yolu, başka hangi dillerin etki alanına özgü diller için iyi bir desteğe sahip olmasıdır?

Ruby çok esnek bir sözdizimine sahiptir ve orada tırmık gibi birçok DSL gelişmiştir. Harika, bu iyiliği çok içerir. Ayrıca Lisp makrolarına daha doğrudan benzeyen AST dönüşümlerini de içerir.

İstatistiksel hesaplama dili olan R, fonksiyonların argümanlarını değerlendirmemesini sağlar. Regresyon formülünü belirtmek için bir DSL oluşturmak için bunu kullanır. Örneğin:

y ~ a + b

"k0 + k1 * a + k2 * b formunun bir satırını y'deki değerlere sığdır" anlamına gelir.

y ~ a * b

"k0 + k1 * a + k2 * b + k3 * a * b formundaki bir satırı y içindeki değerlere sığdır" anlamına gelir.

Ve bunun gibi.


2
Groovy'nin AST dönüşümleri Lisp veya Clojure makrolarına kıyasla çok ayrıntılıdır. Örneğin groovy.codehaus.org/Global+AST+Transformations adresindeki 20+ satır Groovy örneği Clojure'da kısa bir satır olarak yeniden yazılabilir, örneğin `` (this (println ~ message)). Sadece bu değil, aynı zamanda kavanozu derlemek, meta verileri veya diğer Groovy sayfasında herhangi bir şeyi yazmak zorunda kalmazsınız.
Vorg van Geir

7

Yakınsama , lispy olmayan bir başka meta programlama dilidir. Ve bir dereceye kadar, C ++ da hak kazanır.

Muhtemelen MetaOCaml Lisp'ten oldukça uzak. Tamamen farklı bir sözdizimi genişletilebilirliği stili, ancak yine de oldukça güçlü için CamlP4'e bir göz atın .

Nemerle , Scala gibi dillere daha yakın olmasına rağmen, Lisp tarzı bir meta programlamaya sahip başka bir genişletilebilir dildir.

Ve Scala'nın kendisi de yakında böyle bir dil haline gelecek .

Edit: En ilginç örneği unuttum - JetBrains MPS . Lispish'ten çok uzak değil, aynı zamanda doğrudan AST seviyesinde çalışan bir editörle metinsel olmayan bir programlama sistemidir.

Edit2: Güncellenmiş bir soruyu cevaplamak için - Lisp makrolarında benzersiz ve istisnai bir şey yoktur. Teorik olarak, herhangi bir dil böyle bir mekanizma sağlayabilir (düz C ile bile yaptım). Tek ihtiyacınız olan, AST'nize erişim ve derleme zamanında kod yürütme yeteneğidir. Bazı yansımalar yardımcı olabilir (türler, mevcut tanımlar vb. Hakkında sorgulama).


Scala bağlantınız açıkça önerilen makroların "Scala sözdizimini değiştiremeyeceğini" söylüyor. (İlginç, bunu bu teklif ve C / C ++ önişlemci makroları arasındaki fark olarak listeliyor!)
ruakh

@ruakh, evet, Converge ve Template Haskell ile aynı yaklaşımdır - makro uygulaması açıkça işaretlenmiştir ve "normal" bir sözdizimi ile karıştırılamaz. Ancak, içinde istediğiniz herhangi bir sözdizimine sahip olabilirsiniz, bu yüzden tartışılabilir bir sözdizimidir. "Lisp olmayan" gereksinimi maalesef seçeneklerinizi böyle dillerle sınırlar.
SK-logic

"Düz C ile bile yaptım": Bu nasıl mümkün olabilir?
Giorgio

@Giorgio, elbette bir derleyiciyi değiştirdim (makrolar ve C için oldukça doğal olan artımlı bir modül derlemesi ekledim).
SK-logic

AST'ye erişim neden gereklidir?
Elliot Gorokhovsky

6

Prolog, aynı ismin bileşik terimlerine çevrilen yeni operatörlerin tanımlanmasına izin verir. Örneğin, bu bir has_catoperatörü tanımlar ve listenin atom içerip içermediğini kontrol etmek için bir yüklem olarak tanımlar cat:

:- op(500, xf, has_cat).
X has_cat :- member(cat, X).

?- [apple, cat, orange] has_cat.
true ;
false.

xfAracı has_catbir sonek operatörüdür; kullanmak fxonu bir önek operatörü xfxyapar ve iki argüman alarak onu bir infix operatörü yapar. Prolog'da operatör tanımlama hakkında daha fazla bilgi için bu bağlantıyı kontrol edin .


5

TeX listede tamamen eksik. Hepiniz biliyorsunuz, değil mi? Şuna benziyor:

Some {\it ``interesting''} example.

… Ancak sözdizimini kısıtlama olmadan yeniden tanımlayabilirsiniz. Dildeki her (!) Jetona yeni bir anlam atanabilir. ConTeXt , kıvırcık parantezleri kare parantezlerle değiştiren bir makro paketidir:

Some \it[``interesting''] example.

Daha yaygın olan makro paketi LaTeX , dili, \begin{environment}…\end{environment}sözdizimini eklemek gibi amaçları için de yeniden tanımlar .

Ama burada bitmiyor. Teknik olarak, aşağıdakileri ayrıştırmak için simgeleri de yeniden tanımlayabilirsiniz:

Some <it>“interesting”</it> example.

Evet, kesinlikle mümkün. Bazı paketler bunu alana özgü küçük diller tanımlamak için kullanır. Örneğin, TikZ paketi teknik çizimler için aşağıdakilere izin veren özlü bir sözdizimi tanımlar:

\foreach \angle in {0, 30, ..., 330} 
  \draw[line width=1pt] (\angle:0.82cm) -- (\angle:1cm);

Dahası, TeX Turing'i tamamlıyor, böylece kelimenin tam anlamıyla onunla her şeyi yapabilirsiniz . Bunun tam potansiyeline alıştığını hiç görmedim çünkü oldukça anlamsız ve çok kıvrımlı olurdu, ancak aşağıdaki kodu sadece simgeleri yeniden tanımlayarak ayrıştırılabilir hale getirmek tamamen mümkün (ancak bu muhtemelen ayrıştırıcının fiziksel sınırlarına gidecekti. inşa edildiği şekilde):

for word in [Some interesting example.]:
    if word == interesting:
        it(word)
    else:
        word

5

Boo , sözdizimsel makrolar aracılığıyla dili derleme zamanında büyük ölçüde özelleştirmenizi sağlar.

Boo'nun "genişletilebilir bir derleyici boru hattı" vardır. Bu, derleyicinin derleyici boru hattı sırasında herhangi bir noktada AST dönüşümleri yapmak için kodunuzu çağırabileceği anlamına gelir. Bildiğiniz gibi, Java Generics veya C # Linq gibi şeyler derleme zamanında sadece sözdizimi dönüşümleridir, bu oldukça güçlüdür.

Lisp ile karşılaştırıldığında, ana avantajı bunun her türlü sözdizimiyle çalışmasıdır. Boo, Python'dan esinlenilmiş bir sözdizimi kullanıyor, ancak C veya Pascal sözdizimiyle genişletilebilir bir derleyici yazabilirsiniz. Makro derleme zamanında değerlendirildiği için performans cezası yoktur.

Lisp ile karşılaştırıldığında dezavantajları:

  • Bir AST ile çalışmak s ifadeleriyle çalışmak kadar zarif değil
  • Makro derleme zamanında çağrıldığından, çalışma zamanı verilerine erişimi yoktur.

Örneğin, yeni bir kontrol yapısını şu şekilde uygulayabilirsiniz:

macro repeatLines(repeatCount as int, lines as string*):
    for line in lines:
        yield [| print $line * $repeatCount |]

kullanımı:

repeatLines 2, "foo", "bar"

daha sonra derleme zamanında aşağıdaki gibi bir şeye çevrilir:

print "foo" * 2
print "bar" * 2

(Ne yazık ki, Boo'nun çevrimiçi belgeleri her zaman umutsuzca modası geçmiş ve bunun gibi gelişmiş şeyleri bile kapsamıyor. Bildiğim dil için en iyi belgeler bu kitap: http://www.manning.com/rahien/ )


1
Bu özellik için web belgeleri şu anda bozuk ve Boo kendim yazmıyorum, ama gözden kaçarsa yazık olacağını düşündüm. Mod geri bildirimini takdir ediyorum ve boş zamanlarımda ücretsiz bilgilere nasıl katkıda bulunacağımı yeniden değerlendireceğim.
Dan

4

Mathematica değerlendirmesi , kalıp eşleştirme ve değiştirmeye dayanmaktadır. Bu, kendi kontrol yapılarınızı oluşturmanıza, mevcut kontrol yapılarını değiştirmenize veya ifadelerin değerlendirilme şeklini değiştirmenize olanak tanır. Örneğin, "bulanık mantığı" şu şekilde uygulayabilirsiniz (biraz basitleştirilmiş):

fuzzy[a_ && b_]      := Min[fuzzy[a], fuzzy[b]]
fuzzy[a_ || b_]      := Max[fuzzy[a], fuzzy[b]]
fuzzy[!a_]           := 1-fuzzy[a]
If[fuzzy[a_], b_,c_] := fuzzy[a] * fuzzy[b] + fuzzy[!a] * fuzzy[c]

Bu, önceden tanımlanmış mantıksal işleçlerin değerlendirmesini geçersiz kılar &&, || ,! ve yerleşik Iffıkra.

Bu tanımları işlev tanımları gibi okuyabilirsiniz, ancak asıl anlamı şudur: Bir ifade sol tarafta açıklanan desenle eşleşirse, yerine sağ taraftaki ifade gelir. Kendi If yan tümcenizi şu şekilde tanımlayabilirsiniz:

myIf[True, then_, else_] := then
myIf[False, then_, else_] := else
SetAttributes[myIf, HoldRest]

SetAttributes[..., HoldRest] değerlendiriciye, desen eşleşmesinden önce ilk argümanı değerlendirmesi gerektiğini söyler, ancak desen eşleştirilip değiştirilene kadar geri kalanı için değerlendirme yapar.

Bu, Mathematica standart kitaplıklarında yaygın olarak kullanılır; örneğin D, bir ifadeyi alan ve sembolik türevini değerlendiren bir işlevi tanımlamak için .


3

Metalua , bunu sağlayan Lua ile uyumlu bir dil ve derleyicidir.

  • Lua 5.1 kaynakları ve bayt kodu ile tam uyumluluk: temiz, zarif anlambilim ve sözdizimi, muhteşem ifade gücü, iyi performanslar, evrensel kullanıma yakın taşınabilirlik. - Lisp lehçeleri veya Şablon Haskell tarafından sunulanlara benzer şekilde tam bir makro sistemi; manipüle edilmiş programlar
    kaynak kodu, soyut sözdizimi ağaçları veya
    bunların rastgele bir karışımı olarak görülebilir .
  • Dinamik olarak genişletilebilir bir ayrıştırıcı.

  • Tamamı normal metalua makroları olarak uygulanan bir dizi dil uzantısı.

Lisp ile Farklar:

  • Bir yazmadıkları zaman geliştiricilere makroları rahatsız etmeyin: dilin sözdizimi ve anlambilimi, makro yazmadığımız zamanların% 95'i için en uygun olmalıdır.
  • Geliştiricileri dilin kurallarını izlemeye teşvik edin: sadece "en iyi uygulama sıralaması" ile değil, kimse dinlemez, aynı zamanda Metalua Yolu yazmayı kolaylaştıran bir API sunarak. Diğer geliştiriciler tarafından okunabilirlik, derleyiciler tarafından okunabilirlikten daha önemli ve başarılması daha zordur ve bunun için ortak bir saygın kurallar dizisine sahip olmak çok yardımcı olur.
  • Yine de, kişinin istediği tüm gücü sağlayın. Ne Lua ne de Metalua zorunlu esaret ve disipline girmez, bu yüzden ne yaptığınızı biliyorsanız, dil yolunuza girmez.
  • İlginç bir şey olduğunda bunu açıkça belirtin: tüm meta işlemler + {...} ve - {...} arasında gerçekleşir ve görsel olarak normal koddan çıkar.

Bir uygulama örneği, ML benzeri desen eşleşmesinin uygulanmasıdır.

Ayrıca bakınız: http://lua-users.org/wiki/MetaLua


Lua gerçekten bir Lisp olmasa da, "farklılıklar" listeniz oldukça şüphelidir (tek alakalı öğe sonuncusudur). Ve elbette, Lisp topluluğu, zamanın% 95'inde makrolar yazmamalı / kullanmamalı diye bir anlaşmaya katılmayacaktı - Lisp yolu, makroların üstünde DSL'leri kullanarak ve yazarken zamanın% 95'i gibi bir şeye doğru eğiliyor elbette.
SK-logic

2

Genişletilebilir diller arıyorsanız, Smalltalk'a bir göz atmalısınız.

Smalltalk'ta programlamanın tek yolu dili genişletmektir. IDE, kütüphaneler veya dilin kendisi arasında hiçbir fark yoktur. Hepsi o kadar iç içe ki, Smalltalk'a genellikle dil yerine bir ortam deniyor.

Smalltalk'ta tek başına uygulamalar yazmazsınız, bunun yerine dil ortamını genişletirsiniz.

Check out http://www.world.st/ kaynakların ve bilginin bir avuç.

Pharo'yu Smalltalk dünyasına giriş lehçesi olarak tavsiye etmek istiyorum: http://pharo-project.org

Umarım yardımcı olmuştur!


1
Kulağa ilginç geliyor.
Thomas Eding

1

Bütün bir derleyiciyi sıfırdan yazmadan özel diller yapmanıza izin veren araçlar vardır. Örneğin, , bir kod dönüştürme aracı olan Spoofax : giriş dilbilgisi ve dönüşüm kurallarını (çok yüksek düzeyde bildirici bir şekilde yazılmış) koyuyorsunuz ve sonra Java kaynak kodu (veya yeterince önemsiyorsanız başka bir dil) oluşturabilirsiniz. sizin tarafınızdan tasarlanan özel bir dilden

Bu nedenle, X dilinin gramerini almak, X 'dilinin dilbilgisini (özel uzantılarınızla X) ve X' → X dönüşümünü tanımlamak mümkün olacaktır ve Spoofax bir X '→ X derleyicisi oluşturacaktır.

Şu anda, doğru anlarsam, Java için en iyi destek C # desteği geliştirildi (ya da duydum). Bu teknik, statik dilbilgisi olan herhangi bir dile uygulanabilir (yani, muhtemelen Perl değil ).


1

ileri olarak, oldukça genişletilebilir olan başka bir dildir. Birçok Forth uygulaması, çevirici veya C ile yazılmış küçük bir çekirdekten oluşur, daha sonra dilin geri kalanı Forth'da yazılır.

Ayrıca Forth'tan esinlenen ve bu özelliği paylaşan Faktör gibi yığın tabanlı diller de vardır .


0

Funge-98

Funge-98'in parmak izi özelliği, dilin tüm sözdiziminin ve anlambiliminin tamamen yeniden yapılandırılmasını sağlamak için yapılabilir. Ancak yalnızca uygulayıcı kullanıcının dili programlama yoluyla değiştirmesine izin veren bir parmak izi mekanizması sağlarsa (bu teorik olarak normal Funge-98 sözdizimi ve anlambilimi içinde uygulamak mümkündür). Öyleyse, dosyanın geri kalanı (veya dosyanın herhangi bir kısmı) C ++ veya Lisp (veya istediği her şey) gibi davranabilir.

http://quadium.net/funge/spec98.html#Fingerprints


önceki yanıtınıza eklemek yerine bunu neden ayrı olarak gönderdiniz ?
gnat

1
Çünkü Funge'nin Haskell ile bir ilgisi yok.
Thomas Eding

-1

Aradığınızı elde etmek için gerçekten bu parantezlere ve sözdizimi eksikliğine ihtiyacınız var. Sözdizimi tabanlı birkaç dil birbirine yaklaşabilir, ancak gerçek bir makro ile aynı şey değildir.

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.