3 poin oleh GN⁺ 2024-05-03 | 1 komentar | Bagikan ke WhatsApp

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
      1. Pengenalan karakter kurung siku kiri/kanan (yang pada dasarnya adalah notasi prefix)
      2. 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
    1. [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. 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]
    1. 2
    • CLIB adalah function pointer yang menunjuk ke built-in crank
  • Eksekusi swap: 3. 2crank 2. [CLIB]
    1. 2
  • Eksekusi quote (built-in untuk mengutip top-of-stack): 3. 2crank 2. [CLIB]
    1. [2]
  • Eksekusi prepose (mirip dengan compose di Stem, tetapi ditempatkan di depan dan disebut VMACRO): 2. 2crank
    1. ([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

 
GN⁺ 2024-05-03
Komentar Hacker News

Beberapa poin utama yang dapat diringkas:

  • Pada bagian pembukaan dokumen, penjelasan tentang proyek Cognition muncul terlalu terlambat. Akan lebih baik jika informasi paling penting disampaikan lebih awal untuk menghemat waktu pembaca.
  • Seperti fitur pengaturan layer reader di Racket, sudah ada pendekatan lain yang mempertahankan interoperabilitas sambil tetap memperluas sintaks. Diragukan apakah pendekatan Cognition ini secara fundamental benar-benar "lebih baik".
  • Common Lisp juga dapat mengubah sintaks secara fleksibel lewat reader macro, macro, compiler macro, dan sejenisnya. Metaprogramming pada dasarnya menangani semantik, bukan sintaks.
  • Kemampuan Cognition untuk mendefinisikan, mendefinisikan ulang, dan masuk-keluar struktur sintaks pada runtime terasa indah dan menarik. Membuka kemungkinan untuk membuat mesin yang benar-benar "berpikir".
  • Sintaks memberi struktur, sehingga menghapus sintaks itu sendiri bersifat kontradiktif. Sintaks yang terlalu ringkas malah dapat mengurangi keterbacaan dan pemahaman.
  • Cara penulisan dokumennya sendiri terasa cukup panjang dan bernuansa sarkastik sehingga agak sulit dibaca. Namun isinya membahas materi yang cukup mendalam.