Cognition programlama dili tanıtımı
Sorun
- Lisp programcıları, S-ifadeleri kodu ve fonksiyonel makro sistemiyle metaprogramlama ve genelleştirilmiş sistemler kurabileceklerini iddia eder
- Ancak Lisp'in temel bir sorunu var
- Metaprogramlama ile normal programlama aynı olmadığı için Lisp'te her zaman katı bir sözdizimi vardır (parantezler veya look-ahead için bazı karakterler)
- Sol parantez, Lisp'e sağ parantezle karşılaşana kadar okumaya devam etmesi gerektiğini söyler
- Bu, sol ve sağ parantezleri dil içinde değiştirilemez hale getirir (kuramsal olarak değil, bazı uygulamalarda olanaksızdır)
- Daha da önemlisi, bu token'ların ayrıştırıldığı sırayı string işleme olmadan sonradan değiştirmek mümkün değildir
- Diğer dillerde de belirli bir token'a bakarak ileri okunacak içeriği belirleyen farklı yollar vardır
- Bu sürece sözdizimi (syntax) denir
- Cognition ise tamamen postfix kullanan bir anti-syntax (antisyntax) ile ayrılır
- Bu, concatenative programlama dillerine benzer, ancak bu dillerde de iki büyük sorun vardır
- Sol/sağ köşeli parantez karakterleri eklemek (aslında bu prefix sözdizimidir)
- Dize için tırnak karakterleri
- Bu, sıradan bir dil için uygun değildir
- Lisp'in C sözdizimi uygulamasında da aynı sorunlar görüldü (aşırı kaçış karakteri kullanımı, belirli bir token'ın başlangıç ve bitişini ayırmak için boşluk karakterine gerek duymak)
- Racket makro sistemine sahip olsa da runtime'da dinamik değildir ve pre-processing kullanır
Cognition tanıtımı
- Matthew Hinton ile birlikte aylarca üzerinde çalıştığımız bir proje
- Tamamen postfix kullanarak bilinen en genel sözdizimi sistemlerinden biri oluşturmayı hedefliyor
- Sözdizimi, tokenleştirme ve ayrıştırma hakkında geçmiş bilgi gerekebilir ama anlaşılır kılmaya çalışıyoruz
- Repo: https://github.com/metacrank/cognition
Baremetal Cognition
- Baremetal Cognition Brainfuck ile benzer ama ciddi metaprogramlama olanağı sunuyor
- Bootstrap kod örneği:
ldfgldftgldf dfiff1 crank f
- Boşluk ve yeni satır önemlidir
-
- satırda
df sonrası bir boşluk bulunur
-
- satırda bir boşluk karakteri bulunur
- Bu sayede delimiter (sınırlayıcı) ve ignore (yoksayma) adlı iki yeni kavram tanıtılabilir
Tokenization
- Delimiter (Sınırlayıcı), tokenizer'ın token'ın başlangıcını ve sonunu ayırmasını sağlar
- Tek karakterli tokenizer listesi açıktır; Cognition içinde okunup değiştirilebilir
- Ignored character (Yoksayılan karakter), tüm read-eval-print döngüsünün ilk adımında tokenizer tarafından tamamen göz ardı edilir
- Yani token toplama başlamadan önce ayarlanmış yoksayılmış karakter kümesi atlanır
- Varsayılan olarak her karakter bir delimiter'dir ve yoksayılan karakter yoktur
- Delimiter ve ignored listeleri için verilen karakterlerde blacklist/whitelist geçişi yapılabilir (hem kısa hem de pratik kullanım için)
Falias
- Falias, yığına konulduğunda çalışan kelimelerin listesidir
- Tüm Falias'lar yığının üstündeki öğeyi çalıştırır (
Stem'deki eval ile eşdeğerdir)
f varsayılan Falias'tır; yığına konulmaz, doğrudan yığının üstündeki d çalıştırılır
d, delimiter listesini kelimenin string değeriyle değiştirir (yani sadece l karakterini delimiter dışı bırakır)
- Temel ortamda özel Falias'lar dışında hiçbir kelime çalıştırılmaz
Delimiter notları
- Delimiter'larda ilginç bir kural var
- Tokenleştirme döngüsünde bir karakter ignore edilmediyse, delimiter karakteri mevcut token'ın parçası olarak dahil edilir ve devam eder
- Bu, singlet ile tersidir (singlet, token içinde kendisini dahil edip atlar; böylece token toplama sona erer)
- Kara liste durumu da ayarlanabilir
- Delimiter, singlet ve ignored listeleri blacklist/whitelist yapılabilir
- Varsayılan olarak kara listeye alınmış delimiter ile beyaz listeye alınmış singlet veya ignored karakter yoktur
- Diğer tüm karakterler, delimiter veya singlet kurallarıyla döngü durana kadar mevcut token'a eklenir
Bootstrap kodu devam ediyor
ldf
l delimiter olmayan karakter yapılır
gldftgldfdtgldf dfiff1 crank f
d bir delimiter olduğu için gl yığına konur, Falias f çağrılarak gl delimiter olmayan karakter yapılır
tgl yığına konur ve df ile delimiter olmayan karakter olur
dtgl yığına konur ve \ndf ile yeni satır (\n) tek delimiter olmayan karakter olur (yeni satır gerçek kodda yer alır)
- Delimiter kuralı gereği boşluk karakteri ve
\n yığına konur (3. satırda boşluk bulunur)
- Başka bir
\ \n kelimesi tokenleştirilir
- Mevcut yığın şu şekildedir (alttan üste):
3. dtgl
2. [boşluk karakteri]\n
- [boşluk karakteri]\n
df, \ \ni delimiter olmayan karakter olarak ayarlar
if, \ \ni ignored karakter olarak ayarlar (tokenleme başlangıcında ignore edilir)
f, dtglyi çalıştırarak dflagi toggle eder; bu, delimiter blacklist/whitelist ayrımını saklar
- Şimdi delimiter olmayan her şey delimiter olurken, delimiter'ların tümü delimiter olmayan karakter olur
- Son olarak, boşluk ve yeni satır token delimiter'ı olur ve token başlangıcında ignore edilir
- Sonra
1 tokenleştirilip yığına konur; ardından crank kelimesi tokenleştirilir ve f tarafından çalıştırılır (1 tokeni burada sayı olarak ele alınsa da Cognition'da her şey bir kelimedir)
- Bootstrap dizisi tamam!
crankin ne yaptığı bir sonraki bölümde açıklanıyor
Bootstrap özeti
- Cognition ile tokenize etme yaklaşımını programatik olarak, dinamik biçimde değiştirmek mümkün
- Başka dillerde mümkün değildir
- Farklı bir dil için tokenizer'ı Cognition içinde programlayıp istediğiniz gibi tokenize edebilirsiniz
- Postfix kullanıldığı ve look-ahead yapılmadığı için mümkün olur
- Bir ifadeyi değerlendirmeden önce bir veya daha fazla token ayrıştırılması gerekmez
- Falias sayesinde prefix kelimeler veya temel kelime çalıştırmadan da kelime çalıştırılabilir
Crank
- metacrank sistemi, yığında tokenleri çalıştırmanın varsayılan yöntemini ayarlamaya izin verir
crank kelimesi bir sayı argümanı alır; stack'e n adet kelime konduğunda üst öğeyi çalıştırır
- Örnek kod (
crank 1 ayarlanmış halde):
5 crank 2
crank 2 crank
1 crank unglue swap quote prepose def
crank 1 ortamında token değerlendirmesi sırasında f kullanımı devre dışı bırakılabilir
- Tokenleştirilmiş 1 token başına 1 token evaluate edilir
- Sonuç olarak, satır sonu ve boşlukla ayrılmış sözdizimi programlandığı için kodu sezgisel okuyabilirsiniz
- Kod, değerlendirme için
5 den başlar (builtin olmadığı için kendisiyle değerlendirilir)
crank, 5 token yığına her konduğunda çalıştırılacak biçimde ayarlanır
2crank, 2, crank ve 1 yığına konulur (crank 5 ile ayarlandığı için crank bir builtin olsa da execute edilmez):
4. 2crank
3. 2
2. crank
- 1
crank beşinci kelime olduğu için execute edilir (crank 1 ayarıyla)
unglue, builtin olup yığının en üstündeki kelimenin değerini alır (1 tarafından kullanılana göre)
- Yani
crank builtiniyle bağlantılı function pointer alınır
- Yığın şu şekildedir:
3. 2crank
2. 2
- [CLIB]
- CLIB,
crank builtiniyle bağlantılı bir function pointer'dır
swap çalıştırılır:
3. 2crank
2. [CLIB]
- 2
quote (yığının üstündeki öğeyi alıntılayan builtin) çalıştırılır:
3. 2crank
2. [CLIB]
- [2]
prepose (stem'deki composea benzer, ancak VMACRO denilen yere öne yerleştirilir) çalıştırılır:
2. 2crank
- ([2] [CLIB])
def çağrılır
2 yığını ekleyip crank builtini'ne işaret eden fonksiyon pointerını çağıran 2crank kelime tanımı yapılır
- VMACRO'nun ne olduğu, Cognition yığını ile Stem yığını arasındaki farkın açıklanması gerekir
Stem ile farklar
- Stem yığınında kelimeler doğrudan yığına konulabilir
- Cognition'da kelime evaluate edilmeden bir container içine konur ve oradan yığına atılır
- Stem'de
compose gibi bir kelime, bir kelimeyle (veya tek kelime içeren bir container ile) farklı bir container içinde çalışır
- Bu durum Cognition API'sını daha tutarlı hale getirir
cd gibi kelimeler de bu kavramı kullanır
Makro
- Stem quote ile Cognition container arasındaki bir başka fark
- Makro değerlendirmesinde, makronun içindeki her şey evaluate edilir ve crank ignore edilir
- Kelimeye bağlandığında, o kelime değerlendirilirken
1 yorum
Hacker News yorumları
Birkaç temel görüşü özetlemek gerekirse: