Pengenalan Bahasa Pemrograman Cognition
Masalah yang Diangkat
- Pemrogram Lisp mengklaim bahwa mereka bisa membuat metaprogramming dan sistem yang tergeneralisasi dengan kode S-expression dan sistem makro fungsional
- Tapi Lisp memiliki masalah mendasar
- Lisp selalu memiliki sintaks yang ketat (karakter tertentu untuk kurung atau look-ahead)
- Tanda kurung kiri memberi tahu Lisp bahwa ia harus terus membaca sampai menemukan tanda kurung kanan
- Ini membuat tanda kurung kiri/kanan tidak dapat diubah di dalam bahasa (secara konsep tidak demikian, tetapi pada beberapa implementasi memang tidak memungkinkan)
- Yang lebih penting, mengubah urutan pembeda token ini secara kemudian tidak mungkin dilakukan tanpa pemrosesan string
- Bahasa lain juga memiliki cara lain untuk menentukan isi apa yang harus dibaca berikutnya berdasarkan token tertentu
- Proses ini disebut sintaks (syntax)
- Cognition berbeda karena memakai anti-sintaks (antisyntax) berbasis notasi postfix murni
- Ini mirip dengan bahasa concatenative, tetapi bahasa concatenative juga punya dua masalah utama
- Pengenalan karakter kurung siku kiri/kanan (yang pada dasarnya adalah notasi prefix)
- Karakter tanda kutip untuk string
- Ini tidak cocok untuk bahasa umum
- Masalah yang sama juga ditemui pada implementasi sintaks C di Lisp (terlalu banyak escape character, kebutuhan karakter spasi untuk menandai awal/akhir token tertentu)
- Racket punya sistem makro, tetapi tidak dinamis saat runtime dan memanfaatkan pra-pemrosesan
Pengenalan Cognition
- Proyek yang telah dikerjakan bersama Matthew Hinton selama beberapa bulan
- Tujuannya adalah membuat salah satu sistem sintaks yang paling terumumkan menggunakan notasi postfix penuh
- Mungkin dibutuhkan latar belakang pengetahuan tentang sintaks/tokenisasi/parsing, tetapi penjelasannya dibuat semudah mungkin dipahami
- Repositori: https://github.com/metacrank/cognition
Baremetal Cognition
- Baremetal Cognition mirip Brainfuck, tetapi memungkinkan metaprogramming yang serius
- Contoh kode bootstrap:
ldfgldftgldfdtgldf dfiff1 crank f
- Spasi dan newline penting
- Baris ke-2 memiliki spasi setelah
df
- Baris ke-3 memiliki karakter spasi
- Ini memungkinkan dua konsep baru: delimiter dan ignore
Tokenization
- Delimiter membantu tokenizer membedakan awal dan akhir token
- Daftar tokenizer satu karakter tersedia secara publik dan bisa dibaca/diedit di dalam Cognition
- Ignored character adalah karakter yang sepenuhnya diabaikan oleh tokenizer di tahap pertama setiap read-eval-print loop
- Yaitu melewati kumpulan karakter ignore yang disetel saat mulai mengumpulkan token
- Secara default, semua karakter adalah delimiter dan tidak ada karakter yang diabaikan
- Dengan daftar delimiter dan ignore character, karakter yang diberikan bisa di-toggle blacklist/whitelist (menyediakan kepraktisan dan ringkas)
Falias
- Falias adalah daftar kata yang dieksekusi saat diletakkan ke stack
- Semua Falias mengeksekusi top-of-stack (setara
eval di Stem)
f adalah Falias default, dan mengeksekusi top-of-stack tanpa menempatkannya ke stack
d mengubah daftar delimiter menjadi nilai string dari sebuah kata (misalnya, mengecualikan karakter l dari daftar delimiter)
- Pada lingkungan default, tidak ada kata yang dieksekusi kecuali Falias khusus
Catatan Delimiter
- Delimiter punya aturan menarik
- Jika loop tokenisasi tidak mengabaikan suatu karakter, karakter delimiter dimasukkan ke token saat ini dan pemrosesan berlanjut
- Ini bertentangan dengan singlet (yang dimasukkan ke tokennya sendiri lalu dilewati untuk mengakhiri pengumpulan token)
- Dapat juga mengatur status blacklist
- Bisa membuat daftar delimiter, singlet, dan karakter ignore menjadi blacklist atau whitelist
- Secara default tidak ada delimiter di blacklist, singlet di whitelist, atau karakter ignore di whitelist
- Semua karakter lain dikumpulkan sebagai bagian token saat ini sampai loop berhenti karena aturan delimiter atau singlet
Lanjutan kode bootstrap
ldf
- Menjadikan
l sebagai karakter non-delimiter
gldftgldfdtgldf dfiff1 crank f
- Karena
d adalah delimiter, gl masuk ke stack, lalu Falias f dipanggil dan membuat gl menjadi non-delimiter
tgl masuk ke stack dan menjadi non-delimiter karena df
dtgl masuk ke stack dan dengan \ndf, newline (\n) menjadi satu-satunya karakter non-delimiter (newline memang tercantum di kode nyata)
- Berdasarkan aturan delimiter, karakter spasi dan
\n masuk stack (menyertakan spasi pada baris ke-3)
- Kata
\ \n lain juga ter-tokenisasi
- Stack saat ini menjadi seperti ini (dari bawah ke atas):
3. dtgl
2. [karakter spasi]\n
- [karakter spasi]\n
df mengatur \ \n menjadi non-delimiter
if mengatur \ \n sebagai karakter ignore (diabaikan saat memulai tokenisasi)
f menjalankan dtgl dan men-toggle dflag, yang menyimpan pemisahan whitelist/blacklist delimiter
- Sekarang semua karakter non-delimiter menjadi delimiter, dan semua delimiter menjadi non-delimiter
- Akhirnya spasi dan newline menjadi pemisah token dan diabaikan saat token mulai
- Lalu
1 di-tokenisasi dan masuk stack, lalu setelah kata crank di-tokenisasi ia dieksekusi oleh f (1 diperlakukan sebagai angka dalam kasus ini, tetapi di Cognition semua adalah kata)
- Urutan bootstrap selesai! Penjelasan tentang apa yang dilakukan
crank di bagian berikut
Ringkasan Bootstrap
- Cognition memungkinkan mengubah cara tokenisasi secara dinamis melalui pemrograman
- Sesuatu yang tak mungkin dilakukan di bahasa lain
- Bisa memrogram tokenizer untuk bahasa lain dari dalam Cognition dan meng-tokenisasi sesuai keinginan
- Hal ini dimungkinkan karena memakai postfix dan tidak melakukan look-ahead
- Tidak perlu mengurai lebih dari satu token sebelum mengevaluasi ekspresi
- Dengan Falias, kata bisa dieksekusi tanpa menjalankan kata berawalan atau kata bawaan
Crank
- Sistem metacrank membuat cara default eksekusi token di stack dapat diatur
- Kata
crank menerima angka sebagai argumen dan mengeksekusi top-of-stack setiap kali ada n kata dimasukkan ke stack
- Contoh kode (
crank 1 dalam keadaan disetel):
5 crank 2
crank 2 crank
1 crank unglue swap quote prepose def
- Dalam lingkungan
crank 1, saat evaluasi token penggunaan f dapat dihentikan
- Setiap token yang di-tokenisasi mengevaluasi tepat 1 token
- Karena memrogram sintaks yang dibatasi newline/spasi, kode dapat dibaca secara intuitif
- Kode dimulai dengan mencoba mengevaluasi
5 (karena bukan built-in, diperlakukan sebagai dirinya sendiri)
crank di-set agar dieksekusi saat 5 kata diletakkan ke stack
2crank, 2, crank, 1 semuanya masuk ke stack (crank 5 sudah disetel sehingga crank adalah built-in, tapi tidak dieksekusi):
4. 2crank
3. 2
2. crank
- 1
- Karena
crank adalah token ke-5, maka dieksekusi (crank 1 disetel)
unglue adalah built-in yang mengambil nilai kata teratas stack (dengan 1 digunakan)
- Artinya, itu mengambil function pointer yang terhubung ke built-in
crank
- Stack berikutnya:
3. 2crank
2. [CLIB]
- 2
- CLIB adalah function pointer yang menunjuk ke built-in
crank
- Eksekusi
swap:
3. 2crank
2. [CLIB]
- 2
- Eksekusi
quote (built-in untuk mengutip top-of-stack):
3. 2crank
2. [CLIB]
- [2]
- Eksekusi
prepose (mirip dengan compose di Stem, tetapi ditempatkan di depan dan disebut VMACRO):
2. 2crank
- ([2] [CLIB])
- Panggilan
def
- Mendefinisikan kata
2crank dengan meletakkan 2 dan memanggil function pointer yang menunjuk built-in crank
- Diperlukan penjelasan tentang apa itu VMACRO dan apa perbedaan stack Cognition dengan stack Stem
Perbedaan dengan Stem
- Pada stack Stem, kata bisa langsung diletakkan ke stack
- Di Cognition, kata tidak dievaluasi lalu diletakkan ke stack, tetapi ditempatkan ke container lalu diletakkan ke stack
- Pada Stem, kata seperti
compose bekerja pada container kata lain (atau container dengan satu kata) yang berbeda
- Ini membuat API Cognition lebih konsisten
- Konsep ini juga dipakai oleh kata seperti
cd
Makro
- Perbedaan lain antara quote Stem dan container Cognition
- Saat evaluasi macro, semua yang ada di dalam macro dievaluasi dan
crank diabaikan
- Jika dibinding ke sebuah kata, saat kata tersebut dievaluasi,
1 komentar
Komentar Hacker News
Beberapa poin utama yang dapat diringkas: