Cognition: Bahasa antisyntax baru yang mendefinisikan ulang metaprogramming
(ret2pop.nullring.xyz)- Cognition adalah proyek riset bahasa yang memilih antisyntax postfix penuh untuk menghindari masalah read-ahead pada Lisp dan bahasa concatenative
- Perangkat intinya—delimiter, ignore, singlet, falias, crank, dan metacrank—memungkinkan program mengubah aturan tokenisasi dan siklus eksekusinya sendiri
- Bootstrap dimulai dari keadaan yang membaca semua karakter sebagai token tunggal, lalu berpindah sendiri ke lingkungan yang memakai spasi dan newline sebagai pemisah
crankdanmetacrankmengontrol kapan token dievaluasi dan kapan ditumpuk, sehingga sintaks prefix seperti komentar#, escape\, quote[, dan macro(bisa didefinisikan di dalam sistem postfix- Dialek Brainfuck juga diimplementasikan bukan sebagai parser terpisah, melainkan dengan kata Cognition dan aturan tokenisasi, menunjukkan arah untuk menjadikan sintaks itu sendiri sebagai kode dan mengotomatisasikannya
Titik masalah Cognition pada sintaks yang ada
- Lisp menyediakan metaprogramming yang kuat lewat s-expression dan sistem macro, tetapi tetap dipengaruhi oleh sintaks tetap
- Kurung kiri adalah sinyal bahwa pembacaan harus berlanjut sampai kurung kanan muncul, sehingga sulit, atau dalam sebagian implementasi mustahil, mengubah peran kurung dari dalam bahasa
- Untuk mengubah cara pemisahan token yang sudah dibaca di kemudian hari, diperlukan banyak pemrosesan string
- Proses melihat input saat ini lalu harus membaca lebih jauh ke depan adalah syntax, dan begitu read-ahead dasar diasumsikan, bahasa menjadi terikat pada bentuk sintaks tertentu
- Cognition memakai antisyntax bergaya postfix penuh untuk menghindari hal ini
- Mirip dengan bahasa concatenative, tetapi bahasa concatenative umum pun dianggap memiliki masalah read-ahead karena kurung siku atau karakter quote string
- Sistem macro Racket dibedakan sebagai pendekatan yang memakai prapemrosesan, bukan perubahan sintaks dinamis saat runtime
Proyek dan ide dasar
- Cognition adalah proyek riset aktif yang dikerjakan selama beberapa bulan bersama Matthew Hinton
- Repositori implementasinya ada di cognition-rust, dan repositori tersebut juga memuat makalah tentang bahasanya
- Latar belakang tentang parsing, tokenisasi, dan sintaks akan membantu untuk memahaminya
- Penjelasannya berangkat dari kode “baremetal cognition” lalu mengikuti alur perkembangannya menjadi sintaks yang mirip dengan Stem
Baremetal Cognition dan tokenisasi
- Baremetal Cognition sekilas tampak mirip dengan Brainfuck, tetapi mampu melakukan metaprogramming yang lebih kuat
- Kode bootstrap yang sangat kecil menggunakan spasi dan newline secara bermakna, dan pada keadaan awal semua karakter tunggal dibaca sebagai token
- Cognition pada dasarnya dirancang berbasis stack, tetapi memakai istilah container dalam arti yang lebih umum daripada stack
- Dalam lingkungan dasar, tidak ada kata yang dieksekusi otomatis kecuali falias khusus
-
delimiter, ignore, singlet
- delimiter memungkinkan tokenizer mengetahui akhir satu token dan awal token berikutnya
- Daftar delimiter karakter tunggal dapat diubah dan dibaca di dalam kode Cognition
- Karakter ignore dilewati pada tahap awal pengumpulan token di setiap read-eval-print loop
- Nilai defaultnya adalah semua karakter merupakan delimiter dan tidak ada karakter ignore
- Daftar delimiter, singlet, dan ignore dapat mengubah perilakunya dengan flag whitelist/blacklist
- Pengaturan defaultnya adalah tidak ada delimiter yang di-blacklist, tidak ada singlet yang di-whitelist, dan tidak ada karakter ignore yang di-whitelist
- singlet adalah kategori tokenisasi ketiga yang memasukkan dirinya sendiri ke token lalu mengakhiri pengumpulan token
-
falias
- falias adalah daftar kata yang langsung dieksekusi begitu masuk ke container
f, falias bawaan, tidak ditumpuk ke container, melainkan mengeksekusi kata paling atas di container- Dalam contoh, ketika
fmengeksekusid,dmengubah daftar delimiter menjadi nilai string dari kata tersebut - Setelah itu bootstrap berlanjut dengan secara bertahap membuat karakter seperti
l,g,t, dandmenjadi non-delimiter, lalu mengubah spasi dan newline menjadi delimiter sekaligus ignore
Lingkungan eksekusi yang dibuat bootstrap
- Bootstrap awal mengubah aturan delimiter dan ignore hingga akhirnya membentuk lingkungan tempat spasi dan newline menjadi delimiter token, serta spasi dan newline diabaikan pada tahap awal token
- Setelah itu,
1dancrankdibaca, lalufmengeksekusicrankdan masuk ke lingkungan crank 1 - Inti dari proses ini adalah kemampuan mengubah cara tokenisasi saat program berjalan
- Perubahan delimiter, singlet, dan ignore dapat diotomatisasi lewat program
- Karena bergaya postfix dan tidak memiliki read-ahead, tidak perlu mem-parse satu token atau lebih lebih dulu sebelum evaluasi ekspresi
- falias memungkinkan kata tertentu dieksekusi tanpa kata prefix atau eksekusi otomatis kata bawaan
crank dan metacrank
- crank adalah perangkat yang menentukan dalam siklus seperti apa token di atas stack dieksekusi
- Kata
crankmenerima angka sebagai argumen, lalu mengeksekusi stack top untuk setiap kata ke-nyang masuk ke container setelahnya1 crankdi akhir bootstrap membuat lingkungan yang mengevaluasi semua token- Dalam keadaan
5 crank, kata-kata dapat terus ditumpuk sampai token kelima masuk
- Kode contoh memakai
unglue,swap,quote,prepose, dandefuntuk membuat kata bernama2crankungluemengambil nilai kata, dan juga dapat mengambil pointer fungsi builtin seperticrankpreposemirip dengancomposedi Stem, tetapi menambahkan di depan dan memasukkannya ke VMACROdefmendefinisikan2crankagar menaruh2di stack dan memanggil builtincrank
-
Container dan macro di Cognition
- Di Stem, kata dapat diletakkan langsung di stack, tetapi di Cognition kata yang belum dievaluasi masuk ke dalam container
- Berkat desain ini, kata seperti
composedapat menangani container berisi satu kata dan container lain lewat API yang konsisten - Macro di Cognition berbeda dari quote di Stem
- Ketika macro dievaluasi, crank diabaikan dan semua elemen di dalamnya dievaluasi
- Ketika macro yang terikat ke sebuah kata dievaluasi, seluruh macro dijalankan terlepas dari crank, dan cranker hanya bertambah sekali
- Macro berguna untuk kode yang independen dari crank dan expansion untuk tujuan optimasi
-
metacrank
n m metacrankmengatur evaluasi dengan siklusmuntuk elemen yang beradanposisi di bawah stackcranksama dengan0 m metacrank- Untuk satu token, hanya satu metacrank yang dapat dievaluasi, dan metacrank yang lebih rendah mendapat prioritas
- metacrank dan crank diterapkan bukan hanya pada token file, tetapi juga pada proses evaluasi definisi kata secara rekursif
- metacrank memungkinkan manipulasi sintaks langsung seperti “saya ingin menjalankan token ini setelah membaca n token”
- Kata prefix dapat diprogram lalu di-
undefketika tidak lagi diperlukan - Karakter prefix yang berhenti setelah jumlah token tertentu, bukan setelah karakter terminasi tertentu, juga dapat dibuat
- Input pengguna dapat dimasukkan ke program matematika, lalu outputnya diteruskan ke sistem sintaks seperti metacrank
Proses berkembang menjadi dialek Stem
- Setelah bootstrap, Cognition secara bertahap membangun sintaks yang mendekati Stem v2 dari dalam bahasa itu sendiri
- Pertama,
fdihapus dari daftar falias dan hanyaingyang disisakan- Karena
fakan dieksekusi jika diletakkan langsung di stack,ffdibuat lalu string dibelah dua untuk mendapatkan duaf - Setelah itu
fdidefinisikan sebagai kata kosong yang setara dengan false
- Karena
-
Komentar
#- Karakter
#adalah contoh kode pertama yang berperilaku seperti prefix sungguhan - Karakter komentar ini berperilaku sebagai prefix yang membuang teks hingga sebelum newline, membentuk sintaks di mana parser membaca ke depan
- Implementasinya menggabungkan
geti,getd,gets,crankbase,halt,VMACRO cast,singlet,delim, dan lainnya geti,getd, dangetsmasing-masing mengambil ignore, delimiter, dan singlet sebagai stringhaltmembuat semua metacrank menjadi 0VMACRO castmengubah container di stack top menjadi macro- Definisi
#mengubah aturan tokenisasi lalu memanggil#untuk kata yang akan ditokenisasi di masa depan, menjatuhkan komentar tersebut, lalu kembali ke crank dan metacrank semula
- Karakter
-
escape, quote, macro
\didefinisikan sebagai karakter escape yang memungkinkan kata dinaikkan ke stack meski kata itu akan dievaluasi- Setelah itu definisi quote
[ditambahkan, lalu memakai quote tersebut lagi untuk mendefinisikan ulang dirinya sendiri menjadi definisi[yang lebih baik dan memungkinkan quote rekursif - Karena
defbergaya postfix, definisi lama dapat dipakai untuk membuat definisi baru - Pola ini adalah cara pengembangan yang sering dipakai di Cognition level rendah
(didefinisikan sebagai macro bracket- Macro dibuat agar otomatis diekspansi, sehingga mengikat macro yang sudah diekspansi ke sebuah kata dianggap lebih efisien
- Secara fungsional, macro dievaluasi dengan cara yang sama
expandsecara rekursif mengekspansi definisi kata di dalam quote atau macro denganunglue- Setelah mendefinisikan
expanddasar terlebih dahulu,expandsendiri dipakai untuk mendefinisikan ulangnya agar menangani kasus yang lebih umum
Dialek Brainfuck
- Cognition mendefinisikan dialek Brainfuck di atas dialek Stem yang telah berkembang
- Contoh eksekusinya adalah
../crank -s 2 bootstrap.cog helloworld.bf brainfuck.cog brainfuck.cogbukan parser Brainfuck dalam arti umum- Ia mendefinisikan kata-kata Brainfuck
- Ia melakukan tokenisasi Brainfuck
- Ia menjalankannya di lingkungan native Cognition
- Contoh ini menunjukkan bahwa sintaks alternatif dapat didefinisikan dengan mudah menggunakan sintaks Cognition
- Alih-alih membaca simbol lalu menentukan aksi berdasarkan simbol tersebut, Cognition mendefinisikan karakter prefix itu sendiri sebagai kata yang memakai metacrank, sehingga sintaks dimasukkan ke dalam definisi kata
Gagasan dialect dialect
- Dapat dibayangkan kata seperti
mkprefix- Misalnya, sebuah kata yang menerima dua kata input
[dan]serta suatu operasi, lalu secara otomatis mendefinisikan agar[menerapkan operasi tersebut sampai bertemu]
- Misalnya, sebuah kata yang menerima dua kata input
- Gagasan seperti ini mungkin karena
metacrankdandefkeduanya adalah kata biasa - Karena semuanya adalah kata, termasuk
d,i, dans, dialek yang lebih abstrak untuk mengotomatisasi proses implementasi sintaks dapat dibuat - Belum diimplementasikan di standard library, tetapi ada beberapa hal yang telah dibahas bersama Matthew Hinton sebagai kemungkinan untuk standard library
- metaword yang secara otomatis menghasilkan dan memanggil kata abstrak
- Pencarian word-generator untuk mengabstraksikan wordlist saat ini secara otomatis
- Cara mengarahkan framework abstraksi untuk pemecahan masalah
Kemungkinan memperlakukan sintaks sebagai kode
- Di Cognition, pemrosesan string sama dengan post-processing tokenizer, sehingga operasi string memiliki makna yang kuat
- Bidang penerapan potensial yang disebutkan meliputi Symbolic AI, riset sintaks dan grammar, serta eksperimen prototipe bahasa dan metalanguage
- Ada juga ide seperti program pembaca file konfigurasi, shell berbasis Cognition, dan sistem operasi berbasis Cognition
- Intinya, Cognition memungkinkan “syntax as code”
- Sintaks dapat diprogram secara dinamis
- Pembuatan sintaks itu sendiri dapat diotomatisasi
- Konsep seperti Metastack dan
cdtidak dibahas, dan tersisa sebagai topik yang mungkin dibahas dalam tulisan lanjutan
1 komentar
Opini Hacker News
Misalnya, di Racket kita bisa membuat implementasi Datalog tertanam yang memakai sintaks Datalog sekaligus tetap interoperabel dengan modul Racket lain, dan model data dasarnya tidak berubah
Ini cara yang memungkinkan metaprogramming tanpa terkurung dalam S-expression, sambil tetap memprosesnya pada level yang lebih tinggi
Bootstrap sintaks semacam ini keren dan bernilai untuk riset, tetapi saya tidak tahu apakah secara fundamental lebih baik daripada pendekatan Racket
Macro Lisp, Scheme, dan Racket biasanya bekerja di atas AST, tetapi Rhombus bekerja di atas "shrubbery" yang mirip AST namun menunda sebagian keputusan parsing ke tahap berikutnya, sehingga memberi sedikit fleksibilitas untuk perluasan sintaks
Referensi: https://docs.racket-lang.org/guide/hash-reader.html, https://docs.racket-lang.org/datalog/datalog.html, makalah Rhombus https://doi.org/10.1145/3580417
#langdi Racket lebih mudah digunakan daripada readtable CLReadtable saja sudah cukup kuat untuk mengimplementasikan compiler C: https://github.com/vsedach/Vacietis
Secara pribadi, saya tertawa keras di bagian ketika "metacrank" muncul
Di Emacs Lisp, Common Lisp, dan ISLISP, macro hanya menerima data apa pun dan mengembalikan data apa pun; tidak ada konsep seperti AST
Saat memanggil
(foo-macro ...),...bisa berupa data sembarangMisalnya,
(defmacro rev (&rest items) (reverse items))hanya menerima daftar argumen sumber dari pemanggilan macro lalu membalikkannyaIni bisa dipakai seperti
(rev 1 2 3 4 +)atau(rev (rev 10 n -) (+ a 20 b) (rev 30 a *) list), dan yang sebenarnya diteruskan adalah list, angka, dan simbolItu bukan teks dan bukan AST; jika data hasil komputasi diberikan ke
eval, ia tetap bekerja dengan cara yang samaReader Lisp pada dasarnya membaca symbolic expression sebagai layer data, dan EVAL, macro, serta fitur lainnya terutama menerima data
Compiler bisa saja secara internal membuat representasi AST, tetapi itu kebebasan implementasi; bahasa Lisp biasanya didefinisikan di atas sintaks data, bukan sintaks teks
Interpreter Lisp adalah "List Processor" yang memproses S-expression saat berjalan, bukan teks, dan
COMPILEjuga menerima S-expression, bukan teksRacket dan Scheme memiliki sistem macro tersendiri
Sebelum proyek sebenarnya, Cognition, disebutkan, sudah ada lebih dari 300 kata; pembahasan Lisp memang bagus, tetapi saya ragu apakah itu bagian terpenting dari proyek ini
Saat membaca tulisan informatif, saya terus menimbang, "apakah ini layak memakai waktu saya?", jadi dokumen perlu memberi tahu sejak awal tentang apa isinya
Kalimat seperti "Cognition adalah bahasa baru yang mengeksplorasi sintaks yang dapat dimodifikasi pengguna" saja sudah cukup; setelah empat paragraf pertama pun masih sulit menilai apakah tulisan ini layak terus dibaca
Kalau waktu adalah uang, waktu yang dipakai untuk membaca tulisan ini bisa dibilang terbuang
Daripada berharap semua konten di internet disesuaikan dengan selera pribadi, menurut saya lebih baik beradaptasi dengan format yang sudah ada
Teks bukan media yang harus dikonsumsi secara berurutan seperti video, jadi kita bisa membacanya secara diagonal untuk mencari bagian menarik lalu membuangnya jika tidak ada, atau kembali ke awal dan membacanya jika ada
Ragam gaya penulisan lebih baik karena membuat kita secara sadar menyaring informasi yang dikonsumsi; jika hanya mengonsumsi secara pasif, otak jadi malas
Namun, kalau ini video, saya akan setuju
Untuk video, kita harus memutuskan apakah akan menginvestasikan waktu sebelum menontonnya, dan kecepatan 2x atau lompat 5–10 detik memang sedikit membantu, tetapi tidak menyelesaikan masalah
Strukturnya menjelaskan masalah terlebih dahulu, lalu memperkenalkan solusinya
Hanya dengan membaca beberapa kalimat, saya sudah bisa tahu bahwa ini solusi ala Don Quixote untuk sebuah "masalah" yang tidak akan dipedulikan 99,999% orang, termasuk orang seperti saya yang pernah mendengar Lisp tetapi belum pernah memakainya di luar file konfigurasi Emacs; tetapi saya tetap terus membaca
Tanpa bagian seperti ini, isi berikutnya akan lebih sulit dipahami
Jika tidak mengetahui latar belakang itu, kita bisa kehilangan konteks keseluruhan tulisan, dan sulit juga menilai apakah ini argumen orang-orangan jerami
Karena itu, keseluruhannya terasa seperti ada untuk kebutuhan yang sangat sempit, sementara judulnya terlihat jauh lebih umum dan seperti konsep yang cukup menarik
Dalam dua kalimat pertama, sudah tampak masalah apa yang ingin dipecahkan, dan itu jauh lebih berguna untuk mengukur minat saya daripada pembuka yang diusulkan
Namun secara pribadi, ketika menatap tangga kemurnian pemrograman, kira-kira Forth adalah batas kemurnian filosofis yang masih sanggup saya tanggung
Ke depannya kami akan terus membahas lebih banyak sihir gelap
Hanya saja hampir semua bahasa, termasuk semua Lisp, menangani quotation dengan keliru, dan lucunya
m4adalah pengecualianLisp menghindari masalah ini dengan macro, sehingga kalimat bahasa meta yang diekspresikan sebagai kalimat bahasa objek dapat ditangani dengan mengabaikan quoting
Masalah ini muncul karena baik bahasa objek maupun bahasa meta memperlakukan spasi sebagai akhir atom tanpa membedakan keduanya
Pendekatan Cognition berupa antisintaks postfix sepenuhnya mirip dengan bahasa pemrograman konkatenatif, tetapi bahasa postfix adalah dual dari bahasa prefix dan mengalami masalah yang sama
Entah aritas semua simbol harus ditetapkan terlebih dahulu dan tidak memakai fungsi tingkat tinggi, atau diperlukan sepasang delimiter yang dapat menserialisasi tree
Bergantung pada stack implisit orde-0 itu mirip melakukan lobotomi untuk menyembuhkan depresi
Kami sendiri tidak tahu sejauh mana ini sesuatu yang kami ciptakan baru, dan kalau Anda berpikir apa yang kami lakukan bisa dilakukan dengan Lisp, silakan buktikan bahwa kami keliru
m4Klaimnya sendiri menarik, tetapi perlu sesuatu yang lebih konkret
Seperti lobotomi mengurangi kemampuan pemrosesan tingkat tinggi, kembali ke cara paling primitif untuk menghitung string perintah juga bisa dilihat serupa
https://www.hpmuseum.org/rpnvers.htm
Terutama saya suka bahwa mekanismenya sangat kecil
Saya bukan ahli bahasa, jadi tidak tahu apakah ini baru, tetapi sepanjang membaca tulisan itu terasa ada kegembiraan para penulis saat setiap kali melewati bukit mereka menemukan pegunungan kemungkinan baru
Jika saya memahaminya dengan benar, ini berarti dengan Cognition kita benar-benar bisa membuat mesin yang berpikir
Tanpa program harus dihentikan dan dimulai ulang dengan perintah baru, ia dapat menulis dan menjalankan subrutin baru sendiri berdasarkan input baru
Dengan kata lain, program dapat belajar dan beradaptasi sambil membuat abstraksi baru dan terhubung ke API baru
Bagi saya, ini lebih menarik daripada neural network yang lebih besar atau teknik pembelajaran baru
Common Lisp memiliki reader macro, sehingga sintaks dapat diubah sesuka hati, dan bahkan ada compiler Fortran yang membaca sintaks Fortran dengan reader macro
Common Lisp memiliki reader macro pada waktu baca, macro, dan compiler macro pada waktu kompilasi, dan semua bahasa macro ini adalah Common Lisp
Metaprogramming tidak banyak berkaitan dengan macro atau sintaks, melainkan mengacu pada semantik seperti tipe, interface, class, method, dan kemampuan memanipulasi makna
Jika CL sendiri belum cukup kuat, untuk itu ada CLOS, yaitu Common Lisp Metaobject Protocol
Dengan reader macro CL, tokenizer lain memang bisa dipakai, tetapi harus ada ekspresi di dalam read table yang memberi tahu perpindahan tokenizer
Di Cognition, memanggil fungsi tampaknya mengubah tokenizer pada konteks pemanggil
Alasan kita diajari bahwa melakukan hal seperti ini penting dengan mesin Turing atau kalkulus lambda adalah untuk menunjukkan bahwa bahasa tingkat tinggi setara dengan bahasa dasar, sehingga penalaran tentang yang pertama dapat diterapkan juga pada yang kedua
Contoh pertama sekaligus satu-satunya yang terlintas adalah halting problem
Pada skala praktis, kalau bisa membuktikan bahwa bahasa dasar tidak memiliki memory leak, apakah bisa dikatakan bahasa turunannya juga tidak memiliki leak?
Saya penasaran apa keuntungan dari bootstrap semacam ini
Kalau jawabannya sesederhana mendaki Everest karena “ia ada di sana”, itu pun saya hormati
df, spasi di baris 3, dan line break itu penting, saya langsung merasa “terima kasih, tapi tidak usah”Tiga karakter spasi di akhir baris sebelumnya menandakan sindiran, dan di tempat yang sulit membedakan trailing whitespace, silakan ditafsirkan secara harfiah
Bagian bootstrap yang disebutkan itu sebenarnya memberi tahu pembaca untuk memperlakukan spasi dan line break sebagai delimiter
Dengan kata lain, Anda sedang mengeluhkan bahwa spasi punya makna pada bagian yang mendeklarasikannya sebagai delimiter
Tentu Anda berhak berpikir begitu, tetapi saya jadi penasaran apakah ada cara yang lebih baik untuk melakukan ini
Saya tidak terpikir cara melakukan ini tanpa sekali saja membuat spasi literal punya makna seperti itu
Apakah Anda berpikir bisa membaca kalimat seperti “sentence this without you syntax read can” tanpa sintaks?
Cognition katanya memakai antisintaks postfix sepenuhnya, tetapi postfix pun sintaks
Cukup tanya penutur bahasa Jerman tentang verba yang muncul di akhir kalimat
Bahkan pada contoh pertama, urutan operand dan operator itu penting, dan itulah sintaks
Ini terlihat seperti upaya membuat bahasa yang luar biasa padat, dan sangat mengingatkan pada APL
Sebagai petunjuk untuk para penulis, kalian bukan menghilangkan sintaks, melainkan hanya membuatnya sulit dibaca dan dipahami manusia, dan keterbacaan serta keterpahaman adalah unsur penting dalam pemrograman
Rasanya aturan di bawah kaki terus berubah, seolah aturan dan kata diperkenalkan lalu didefinisikan ulang sesukanya
Secara keseluruhan ada nuansa Numberwang, sehingga ini tampak seperti satir, dan itu salah satu alasannya
Alasan besar lainnya adalah tahap bootstrap ditulis dengan cara yang sampai terasa konyol, dan itu tampaknya disengaja
Jelas ada sesuatu yang dalam di sini, tetapi saya perlu membacanya lagi setelah minum kopi yang lebih kuat
Saya penulis tulisan ini, dan masalahnya adalah benar-benar banyak hal yang harus disampaikan
Saya berdiskusi dengan Matthew tentang desain bahasa ini selama 3 minggu, beberapa jam setiap hari, dan ada banyak konteks yang harus diisi untuk orang-orang yang sebenarnya tidak mengenal saya