Homooniklik - Homoiconicity

Gelen bilgisayar programlama , homoiconicity (dan Yunan deyişle homo "aynı" ve anlam simgesi bazılarının bir özelliktir anlamına gelen "temsil") programlama dilleri . Bir dil, içinde yazılan bir program, dil kullanılarak veri olarak manipüle edilebiliyorsa ve bu nedenle programın iç temsili, yalnızca programın kendisini okuyarak çıkarılabilirse , homoikoniktir . Bu özellik genellikle dilin "kodu veri olarak" ele aldığı söylenerek özetlenir.

Bir homoiconic dilinde, programların başlıca gösterimi aynı zamanda bir veri yapısı bir in temel türün dilin kendisinin. Bu, metaprogramlamayı bu özelliği olmayan bir dile göre daha kolay hale getirir : dilde yansıma (programın varlıklarını çalışma zamanında incelemek ) tek, homojen bir yapıya bağlıdır ve karmaşık bir sözdiziminde görünecek birkaç farklı yapıyı ele alması gerekmez. Homoiconic diller tipik olarak sözdizimsel makroların tam desteğini içerir ve programcının programların dönüşümlerini özlü bir şekilde ifade etmesine olanak tanır.

Yaygın olarak anılan örnek Lisp kolay listesi manipülasyonlar ve izin vermek için oluşturulmuş yapı ile verilir burada S ifadeleri şeklinde iç içe listeleri ve diğer Lisp kodu ile manipüle edilebilir. Diğer örnekler, Clojure (Lisp'in çağdaş bir lehçesi), Rebol (aynı zamanda onun halefi Red ), Refal , Prolog ve daha yakın zamanda Julia programlama dilleridir .

Tarih

Orijinal kaynak, erken ve etkili olan TRAC, A Text Handling Language adlı makaleye göre Derleyici Dillerinin Makro Talimat Uzantıları belgesidir :

Ana tasarım hedeflerinden biri, TRAC'ın (kullanıcı tarafından yazılan) girdi komut dosyasının , TRAC işlemcisinin dahili eylemini yönlendiren metinle aynı olması gerektiğiydi. Diğer bir deyişle, TRAC prosedürleri, tam olarak kullanıcının klavyede yazdığı gibi bir karakter dizisi olarak bellekte saklanmalıdır. TRAC prosedürlerinin kendileri yeni prosedürler geliştiriyorsa, bu yeni prosedürler de aynı senaryoda belirtilmelidir. TRAC işlemcisi, eyleminde bu komut dosyasını kendi programı olarak yorumlar. Başka bir deyişle, TRAC çevirme programı (işlemci), bilgisayarı yeni bir program dili olan TRAC dili ile yeni bir bilgisayara etkili bir şekilde dönüştürür. Herhangi bir zamanda, program veya prosedür bilgilerini, TRAC işlemcisinin yürütülmesi sırasında buna göre hareket edeceği biçimde görüntülemek mümkün olmalıdır. Dahili karakter kodu gösteriminin, harici kod gösterimi ile aynı veya çok benzer olması arzu edilir. Mevcut TRAC uygulamasında, dahili karakter gösterimi ASCII'ye dayanmaktadır . TRAC prosedürleri ve metni, işlemcinin içinde ve dışında aynı temsile sahip olduğundan, homo aynı anlama gelen ve simge temsil anlamına gelen homoiconic terimi uygulanabilir.

[...]

McCullough, WS'nin önerisini takiben, Peirce'den kaynaklanan terminolojiye dayalı olarak, CS'den McIlroy. MD, "Derleyici Dillerinin Makro Komut Uzantıları", Comm. ACM, s. 214-220; Nisan, 1960.

Alan Kay , 1969 yılındaki doktora tezinde bu terimi kullanarak "homoikonik" terimini kullandı ve muhtemelen popüler hale getirdi:

Önceki tüm sistemler için dikkate değer bir istisna grubu, Etkileşimli LISP [...] ve TRAC'dir. Her ikisi de işlevsel olarak yönlendirilir (bir liste, diğer dize), her ikisi de kullanıcıyla tek bir dille konuşur ve her ikisi de iç ve dış temsilleri esasen aynı olduğu için "homoikonik"tir. Her ikisi de, daha sonra kullanıcının zevkine göre geliştirilebilecek yeni işlevleri dinamik olarak yaratma yeteneğine sahiptir. Tek büyük dezavantajı, içlerinde yazılan programların Kral Burniburiach'ın Babil çivi yazısıyla yazılmış Sümerlere yazdığı mektup gibi görünmesidir! [...]

Kullanım alanları ve avantajları

Eş sesliliğin bir avantajı, kodu temsil eden veriler programın meta ve temel katmanı arasında geçirilebildiğinden, dili yeni kavramlarla genişletmenin tipik olarak daha basit hale gelmesidir . Anahtar sözdizimi ağacı bir fonksiyonu oluşur ve meta katmanında bir veri yapısı olarak manipüle edilebilir, ve daha sonra olabilir değerlendirildi . Basit veri olarak daha kolay anlaşılabileceğinden (dilin formatı bir veri formatı olduğu için) kodun nasıl değiştirileceğini anlamak çok daha kolay olabilir.

Homoonikliğin tipik bir gösterimi, meta-dairesel değerlendiricidir .

Uygulama yöntemleri

Bugün genel amaçlı bilgisayarların büyük çoğunluğunu içeren tüm Von Neumann mimari sistemleri, ham makine kodunun bellekte yürütülme şekli nedeniyle, veri türü bellekte bayt olduğundan dolaylı olarak homoikonik olarak tanımlanabilir. Ancak bu özellik programlama dili düzeyine de soyutlanabilir.

Lisp gibi diller ve Scheme , Clojure ve Racket gibi lehçeleri, eşseslilik elde etmek için S-ifadelerini kullanır.

Homoik olarak kabul edilen diğer diller şunlardır:

Lisp'te

Lisp , S-ifadelerini veri ve kod için harici bir temsil olarak kullanır . S-ifadeleri ilkel Lisp işleviyle okunabilir READ. READLisp verilerini döndürür: listeler, semboller , sayılar, dizeler. İlkel Lisp işlevi EVAL, Lisp verileri olarak temsil edilen Lisp kodunu kullanır, yan etkileri hesaplar ve bir sonuç döndürür. Sonuç, PRINTLisp verilerinden harici bir S ifadesi oluşturan ilkel işlev tarafından yazdırılacaktır .

Lisp verileri, farklı veri türleri kullanan bir liste: (alt)listeler, semboller, diziler ve tamsayılar.

((:name "john" :age 20) (:name "mary" :age 18) (:name "alice" :age 22))

Lisp kodu. Örnekte listeler, semboller ve sayılar kullanılmıştır.

(* (sin 1.1) (cos 2.03))      ; in infix: sin(1.1)*cos(2.03)

İlkel Lisp işleviyle yukarıdaki ifadeyi oluşturun LISTve değişkeni EXPRESSIONsonuca ayarlayın

(setf expression  (list '* (list 'sin 1.1) (list 'cos 2.03)) )  
-> (* (SIN 1.1) (COS 2.03))    ; Lisp returns and prints the result

(third expression)    ; the third element of the expression
-> (COS 2.03)

Değişim COSteriminiSIN

(setf (first (third expression)) 'SIN)
; The expression is now (* (SIN 1.1) (SIN 2.03)).

İfadeyi değerlendirin

(eval expression)
-> 0.7988834

İfadeyi bir dizgeye yazdır

(print-to-string expression)
->  "(* (SIN 1.1) (SIN 2.03))"

Bir dizeden ifadeyi okuyun

(read-from-string "(* (SIN 1.1) (SIN 2.03))")
->  (* (SIN 1.1) (SIN 2.03))     ; returns a list of lists, numbers and symbols

Girişte

1 ?- X is 2*5.
X = 10.

2 ?- L = (X is 2*5), write_canonical(L).
is(_, *(2, 5))
L = (X is 2*5).

3 ?- L = (ten(X):-(X is 2*5)), write_canonical(L).
:-(ten(A), is(A, *(2, 5)))
L = (ten(X):-X is 2*5).

4 ?- L = (ten(X):-(X is 2*5)), assert(L).
L = (ten(X):-X is 2*5).

5 ?- ten(X).
X = 10.

6 ?-

4. satırda yeni bir yan tümce oluşturuyoruz. Operatör :-, bir tümcenin başını ve gövdesini ayırır. Bunu assert/1*mevcut tümcelere ekleriz ("veritabanı"na ekleriz), böylece daha sonra çağırabiliriz. Diğer dillerde buna "çalışma zamanı sırasında bir işlev yaratmak" derdik. Ayrıca abolish/1, veya ile tümceleri veritabanından kaldırabiliriz retract/1.

* Cümlenin adından sonraki sayı, onun alabileceği argüman sayısıdır. Ayrıca arity denir .

Bir yan tümcenin gövdesini almak için veritabanını da sorgulayabiliriz:

7 ?- clause(ten(X),Y).
Y = (X is 2*5).

8 ?- clause(ten(X),Y), Y = (X is Z).
Y = (X is 2*5),
Z = 2*5.

9 ?- clause(ten(X),Y), call(Y).
X = 10,
Y = (10 is 2*5).

callLisp'in evalişlevine benzer .

Rebol'da

Kodu veri olarak ele alma kavramı ve bunların işlenmesi ve değerlendirilmesi Rebol'de çok net bir şekilde gösterilebilir . (Lisp'ten farklı olarak Rebol, ifadeleri ayırmak için parantez gerektirmez).

Aşağıdaki, Rebol'deki bir kod örneğidir ( >>Yorumlayıcı istemini temsil eden not ; okunabilirlik için bazı öğeler arasına boşluklar eklenmiştir):

>> repeat i 3 [ print [ i "hello" ] ]

1 hello
2 hello
3 hello

( repeataslında Rebol'de yerleşik bir işlevdir ve bir dil yapısı veya anahtar sözcük değildir).

Kodu köşeli parantez içine alarak, yorumlayıcı onu değerlendirmez, sadece onu sözcükleri içeren bir blok olarak değerlendirir:

[ repeat i 3 [ print [ i "hello" ] ] ]

Bu blok tip bloğuna sahiptir! ve ayrıca atama için bir sözdizimi gibi görünen, ancak yorumlayıcı tarafından özel bir tür ( set-word!) olarak anlaşılan ve ardından iki nokta üst üste gelen bir sözcük biçimini alan bir sözcüğün değeri olarak atanabilir :

>> block1: [ repeat i 3 [ print [ i "hello" ] ] ] ;; Assign the value of the block to the word `block1`
== [repeat i 3 [print [i "hello"]]]
>> type? block1 ;; Evaluate the type of the word `block1`
== block!

Blok hala kullanılarak yorumlanabilir do(benzer Rebol'a sağlanan fonksiyonu evalLisp'te ).

Bloğun öğelerini sorgulamak ve değerlerini değiştirmek, böylece değerlendirilecekse kodun davranışını değiştirmek mümkündür:

>> block1/3 ;; The third element of the block
== 3
>> block1/3: 5 ;; Set the value of the 3rd element to 5
== 5
>> probe block1 ;; Show the changed block
== [repeat i 5 [print [i "hello"]]]
>> do block1 ;; Evaluate the block
1 hello
2 hello
3 hello
4 hello
5 hello

Ayrıca bakınız

Referanslar

Dış bağlantılar