- Raku lebih mirip laboratorium fitur bahasa tempat berbagai ide diuji langsung, alih-alih satu desain tunggal yang sangat matang, sehingga kita bisa melihat eksperimen yang layak diadopsi bahasa lain di satu tempat
- Junctions menyebarkan operasi ke himpunan nilai yang mungkin, lalu melipatnya dengan kuantor boolean seperti
all,any, danoneuntuk mengekspresikan kondisi kompleks secara singkat *pada Whatevers dipakai untuk rentang tak terbatas, fungsi anonim, dan pengindeksan berbasis panjang daftar, menghasilkan gaya kode yang ringkas tetapi terasa asing- Regex Raku meninggalkan kompatibilitas PCRE, tetapi sebagai gantinya menawarkan grammar yang bisa dikomposisikan, pemisah nilai, lookahead yang mudah dibaca, dan fitur praktis seperti mengabaikan spasi secara default
- Jika melihat Hyperoperators, Pair Syntax, Slangs, RakuAST, hingga Rakudo Star, Raku adalah bahasa yang bereksperimen luas dari sisi sintaks hingga cara distribusi
Mengapa Raku terlihat seperti laboratorium fitur bahasa
- Setelah benar-benar memakai Raku selama lebih dari setahun, Raku tampak lebih dekat ke bahasa yang berfungsi sebagai laboratorium untuk fitur bahasa
- Lima model konkurensi dan banyak cara melakukan hal yang sama menunjukkan sifat eksperimentalnya, seolah dibuat untuk “melihat apa yang terjadi”
- Banyak fitur berinteraksi secara aneh dan memiliki banyak edge case juga karena menjalankan 100 eksperimen jauh lebih mudah daripada memoles semuanya agar bisa bekerja bersama
- Fitur-fitur yang dibahas di sini adalah eksperimen ala Raku yang mungkin suatu hari akan muncul juga di bahasa pemrograman lain
Junctions: tumpang tindih nilai yang mungkin dan kuantor boolean
- Junctions merepresentasikan tumpang tindih nilai-nilai yang mungkin, dan saat operasi diterapkan ke junction, operasi yang sama diterapkan ke semua nilai di dalamnya
2|10menjadiany(2, 10)2&10 + 3menjadiall(5, 13)(1&2) + (10^20)digabungkan menjadi sesuatu sepertiall(one(11, 21), one(12, 22))
- Kegunaan utama Junctions adalah mengekspresikan rumus boolean seperti
alldanany- Tidak ada cara untuk membongkar struktur junction
- Agar benar-benar berguna, junction harus lebih dulu dilipat menjadi boolean
somemaksa konversi junction menjadi booleanso (1&2) + (10^20) < 15adalahTrueso (1&2) + (10^20) > 0adalahFalse
list.alldi Raku bukan metode yang menerima argumen, melainkan metode tanpa argumen yang mengubah daftar menjadi junction<1 2 3>.allmenjadiall(1, 2, 3)- Jika diterapkan
is-prime($x), hasilnya menjadi sepertiall(False, True, True)
- Dengan menggabungkan Junctions, kita juga bisa membuat perilaku seperti
unique- “Apakah setiap elemen sama dengan tepat satu elemen” dapat ditulis sebagai
{.all == .one} <1 2 3 7>bernilai benar, sedangkan<1 2 3 7 2>bernilai salah
- “Apakah setiap elemen sama dengan tepat satu elemen” dapat ditulis sebagai
Whatevers: rentang tak terbatas dan fungsi anonim dengan *
*pada Whatevers adalah simbol whatever di Raku yang memegang beberapa peran- Dalam rentang atau urutan,
*berarti tidak ada batas1..*adalah1..Inf(2,4,8...*)[17]adalah262144
- Ekspresi yang mengandung
*dipromosikan menjadi fungsi anonim- Perilaku ini disebut whatever-priming
- Hasilnya adalah
WhateverCode, dan selain tipenya, tidak bisa dibedakan dari fungsi lain (* + 10)(2)menghasilkan12(^10).map(* % 2)membuat pola0 1 0 1 ...
- Jika ada dua
*dalam satu ekspresi, masing-masing menjadi argumen posisi yang terpisah(2, 30, 4, 50).map(* + *)mengembalikan(32, 54)- Ini berguna untuk definisi Fibonacci yang rumit, tetapi belum tentu lebih baik daripada pendekatan di mana setiap
*berarti nilai yang sama
- Banyak metode Raku bisa menerima fungsi, sehingga priming dipakai secara luas
l[*-1]terlihat seperti indeks negatif, tetapi sebenarnya[]memberikan panjang daftar ke fungsi lalu memakai hasilnya sebagai indeks- Jika panjang daftar adalah 10, maka
l[*-1]berartil[10-1], yaitu elemen terakhir l.head(2)berarti dua elemen pertama, sedangkanl.head(*-2)berarti seluruh daftar kecuali dua elemen terakhir
- Jika fungsi lain diberikan ke
[], struktur seperti ring buffer juga bisa diimplementasikan dengan sederhana@x[95 % *]--menghitung posisi dengan memakai panjang daftar
Regex: grammar yang bisa dikomposisikan dengan meninggalkan kompatibilitas PCRE
- Raku menggunakan sintaks regex baru yang berbeda dari regex POSIX maupun PCRE
- Regex POSIX adalah struktur yang penuh backslash dan tanda baca
- PCRE kompatibel mundur dengan POSIX dan mewarisi struktur backslash serta tanda baca yang lebih rumit
- Perl 6 memutus kompatibilitas mundur dan memperkenalkan sintaks regex baru
- Perbaikan yang paling menonjol adalah kemampuan komposisi
- Di banyak bahasa, regex digabungkan dengan menyambung string regex
- Raku memungkinkan penyisipan regex lain seperti
/< foo >+/, sehingga regexfoobisa dicocokkan satu kali atau lebih tanpa bocor ke regex induk
- Regex yang kompleks bisa dipecah menjadi bagian-bagian yang lebih kecil dan lebih mudah dibaca
- Pendekatan ini menjadi dasar dukungan Raku terhadap grammar parsing sebagai fitur bawaan bahasa
- Dengan memutus kompatibilitas mundur, beberapa fitur praktis juga ditambahkan
\\d+ % ','mencocokkan1,1,2, dan1,1,4, tetapi tidak mencocokkan1,atau12- lookahead dan non-capturing group bukan lagi kombinasi simbol yang sulit dibaca
r1 && r2hanya mencocokkan string yang memenuhir1danr2sekaligus:bisa dipakai untuk menghentikan backtracking- Spasi diabaikan secara default dan harus diaktifkan secara eksplisit di pola pencocokan
- Terlepas dari kemampuan pemrosesannya sendiri, notasi regex Raku dapat dilihat sebagai kumpulan fitur yang mungkin juga muncul di bahasa lain
Hyperoperators: pemetaan tergeneralisasi yang turun hingga ke daftar bertingkat
- Bentuk dasar Hyperoperators, yaitu
l>>.method, miripmaptetapi turun secara rekursif ke subdaftar[1, [2, 3], 4]>>.succmenjadi[2 [3 4] 5]
- Di Raku, pemanggilan fungsi berbentuk
f(list, *args)bisa diubah menjadi bentuk metodelist.&f(* args)- Karena itu,
>>.bekerja seperti operator pemetaan yang digeneralisasi - Bersama Whatever, ini bisa dipakai seperti
[1, [2, 3], 4]>>.&(*+1)
- Karena itu,
- Hyperoperator biner
l1 << op >> l2menerapkanopper elemen ke dua daftar- Daftar yang lebih pendek diulang sampai daftar yang lebih panjang habis
[1, 2, 3, 4, 5] <<+>> [10, 20]menghasilkan[11 22 13 24 15]- Bentuk
<< op<<atau>>op>>hanya mengulang sampai daftar kiri atau kanan habis
- Ini juga bekerja pada nilai tunggal dan daftar bertingkat
[1, 2, 3, 4, 5] <<+>> 10menghasilkan[11 12 13 14 15][1, [2, 3], 4, 5] <<+>> [10, 20]menghasilkan[11 [22 23] 14 25]
- Hyperoperator untuk dua hash juga memiliki perilaku terpisah yang menerapkan
oppada union, intersection, dan selisih hash - Nama Hyperoperator berasal dari fakta bahwa semua operasi dievaluasi secara paralel
- Bahkan loop eksplisit pun bisa diparalelkan dengan prefiks
hyper
- Bahkan loop eksplisit pun bisa diparalelkan dengan prefiks
Pair Syntax: unit dasar hash dan pengiriman flag yang ringkas
- Pair adalah unit dasar yang menyusun hash di Raku
- Hash adalah kumpulan pasangan
key => value - Pair adalah tipe dasarnya, sedangkan hash adalah koleksi pair
- Hash adalah kumpulan pasangan
- Raku memiliki banyak sintaks colon singkat untuk menulis pair
my $x = 3; :$xberartix => 3:a<$x>berartia => "$x":a($x)berartia => 3:3aberartia => 3
- Singkatan yang paling penting adalah
:keydan:!key- Keduanya dipetakan ke
key => Truedankey => False - Ini dipakai sebagai cara ringkas untuk menambahkan flag ke metode
- Keduanya dipetakan ke
- Metode
matchmenerima banyak colon pair sebagai flag- Bentuk seperti
:continue(:$c),:pos(:$p),:global(:$g), dan:overlap(:$ov)digunakan :f(:$foo)dalam signature mendefinisikan parameter$foosekaligus membuat alias:f- Pemanggil bisa menyetel flag yang sama dengan
:fatau:foo
- Bentuk seperti
- Argumen colon pair fleksibel dalam urutan dan posisinya
"abab".match(/../, :g)melakukan pencocokan global"abab".match(/../, :g, :ov)melakukan pencocokan overlap- Urutannya bisa diubah dan digabung seperti
"abab".match(:g:ov, /../) - Argumen keyword juga bisa diletakkan setelah pemanggilan fungsi seperti
"abab".match(:g, /../):ov:2nd
- Sintaks ini membuat penentuan opsi metode jauh lebih singkat dibanding
match(global=True, overlap=True)
Slangs, RakuAST, Rakudo Star
- Slangs adalah fitur untuk mengubah grammar Raku
- Ini bisa dipakai untuk mengubah sintaks loop, mengganti identifier, menambahkan actor, atau menambahkan sekuens DNA
- Contohnya termasuk Slang::Otherwise, Slang::Piersing, OO::Actors, dan BioInfo
- RakuAST adalah fitur yang mem-parsing ekspresi Raku menjadi AST dari dalam Raku sendiri
Q/my $x; $x++/.ASTmenampilkan deklarasi variabel dan operasi postfix increment dalam bentukRakuAST::StatementList- Ada juga contoh seperti
Q/my $x; put $x/.AST.DEPARSE("NL")yang menampilkan kode Raku dalam notasi ala bahasa lain
- Raku memiliki distribusi instalasi Rakudo Star
- Distribusi ini menyediakan modul pihak ketiga terpilih yang sudah dipasang sebelumnya
- Ini lebih mirip kompromi antara beban pemeliharaan standard library besar dan beban pengguna yang harus mencari sendiri paket yang tepat di ekosistem
1 komentar
Komentar Hacker News
Dulu saya pernah mengimplementasikan secara terpisah sesuatu yang mirip dengan fitur regular expression komposisional yang dibahas di sini untuk JavaScript, dan bahkan setelah beberapa tahun berlalu itu masih menjadi salah satu library yang paling sering saya bawa ke proyek lain
Rasanya sedikit lebih dekat ke seolah-olah ada parser kelas satu di dalam bahasa, dan sebagai contoh ada implementasi parsing media type dengan regex yang memanfaatkannya: https://runkit.com/tolmasky/media-type-parsing-with-template...
npm:
templated-regular-expression, GitHub: https://github.com/tolmasky/templated-regular-expressionTentu saja bahasa pemrograman seharusnya punya parser sungguhan dan regex tidak seharusnya dipakai sebagai parser, tetapi kalau toh akan memakai regex, kemampuan untuk memecahnya menjadi bagian-bagian kecil itu sangat bagus
Regex di Raku, ketika digabungkan dengan grammar, jauh lebih kuat dan, jika ditulis dengan baik, lebih mudah dipahami daripada “parser sungguhan” mana pun. Untuk mem-parse Raku dengan parser biasa, parser itu harus bisa menambahkan dan menghapus entri saat proses parsing berjalan, dan parser Raku menangani ini dengan men-subclass grammar saat ini untuk menambah atau menghapus entri dalam cakupan leksikal saat ini lalu kembali ke grammar sebelumnya ketika cakupan berakhir
Di Raku, regex adalah tata bahasa lain untuk menulis kode, hanya dengan grammar dan perilaku dasar yang sedikit berbeda, dan bisa memiliki parameter serta variabel. Jika ada pekerjaan yang tidak cocok dengan grammar regex, Anda bisa menyisipkan grammar Raku biasa untuk melakukan yang diperlukan lalu kembali lagi ke grammar regex
Sebagai contoh, mencocokkan satu atau lebih
Adiikuti jumlahByang sama dan jumlahCyang sama juga memungkinkan, dan di kebanyakan grammar regex, mencocokkan jumlahAdanByang sama biasanya memerlukan rekursi di tengah, tetapi dengan begitu akan sulit memperlakukanCdengan cara yang sama dan juga jauh lebih sulit dibaca. Pendekatan Raku tidak memerlukan backtracking maupun rekursi sehingga bisa berjalan cukup cepatJika dibungkus sebagai grammar, Anda mendapatkan parse tree lengkap, dan tanpa grammar pun tetap bisa, tetapi memakai grammar lebih mudah. Untuk contoh parser nyata, saya sering merekomendasikan JSON::TINY::Grammar: https://github.com/moritz/json/blob/master/lib/JSON/Tiny/Gra...
Sejujurnya, sebagian besar desain “parser sungguhan” tampak seperti produk sampingan dari keterbatasan RAM pada komputer awal. Tahap tokenisasi terpisah ada untuk mengurangi RAM yang dipakai source code agar menyisakan memori untuk analisis semantik dan kompilasi sesudahnya, dan saya tidak melihat tahap-tahap setelah itu jadi sesederhana itu karenanya. Modul JSON::Tiny di atas pada dasarnya mengompilasi sambil mem-parse, karena grammar-nya membangun struktur data Raku native ke dalam action class selama proses parsing
Saya memakai Raku di produksi. Untuk pemrosesan teks, ini bahasa terbaik, dan pengalaman membuat parser dengannya luar biasa menyenangkan
Yang mengejutkan, ini bukan bahasa tingkat atas untuk membangun pipeline teks LLM
Wow. Saya jadi ingin meninggalkan industri ini sebelum hari ketika saya harus memelihara codebase Raku tiba
Kalau melihat buku-buku pengantar Raku, banyak bagiannya terasa seperti Python dengan sintaks keluarga C. Sintaksnya berpusat pada kurung kurawal, tetapi kemudahan penggunaan, struktur data bawaan, dan fitur berorientasi objeknya semuanya tingkat tinggi
Kalau Anda mengenal bahasa skrip tingkat tinggi lain, saya rasa kode Raku untuk skrip serupa akan cukup mudah dibaca. Saya juga tidak merasa kebanyakan orang akan memakai fitur yang benar-benar aneh dalam kode sehari-hari, dan meskipun Raku lebih fleksibel, kode biasa umumnya tidak terlihat membingungkan
Itu juga terlihat dari kemampuan Raku untuk mendefinisikan argumen keyword dalam bentuk singkat, misalnya
:global(:$g)atau mengasumsikan nilaiTruesehingga bisa memanggil global regex match sepertimatch(/foo/, :g). Perl juga punya banyak hal seperti ini, dan semuanya dibuat agar lebih cepat dan lebih menyenangkan dipakai, tetapi jadi kurang mudah dibaca bagi pemulaSepertinya ini akan menjadi perbedaan generasi. Bisa jadi seluruh generasi programmer yang lebih tua akan merasa tersingkir dari lingkungan kerja yang bagi generasi sekarang terasa normal
Beberapa fitur terasa setengah familier. Hyper terdengar seperti versi yang lebih improvisasional dari sesuatu di sisi recursion-schemes, dan
*yang ditampilkan di sini agak mirip dengan_di Scala_enak dipakai untuk lambda, jadi saya berharap semua bahasa mengadopsi sesuatu yang mirip> (2, 30, 4, 50).map(* + *) returns (32, 45)bukankah seharusnyareturns (32, 54)? Soalnya elemen kedua berarti 4+50Mungkin ini hasil terjemahan lead yang berasal dari cara beberapa negara menyebut angka dalam bahasa Inggris bukan fifty-four melainkan seperti vierenvijftig, “empat dan lima puluh”
(32 54). Sepertinya penulisnya salah ketikJadi sekarang Perl adalah obat gerbang menuju bahasa keluarga APL?
Misalnya, meta-operator reduce
[ ]bisa dipakai bersama+infiks untuk melakukan “menjumlahkan semuanya”:[+] 1, 2, 3Raku masih punya masalah besar pada kecepatan. Mem-parsing file log dengan regex adalah keunggulan Perl, tetapi Raku terbaru pun butuh waktu 6,5 kali lebih lama daripada Python 3.13, bahkan setelah waktu startup dikecualikan
Fakta bahwa
(2,4,8...*)[17]menghasilkan262144benar-benar mengejutkanSelain
Whatever, hal yang terasa baru setelah Perl6/Raku mungkin lebih ke sisi evaluasi malas(1,3,9...*)[4,5]menjadi(81 243), dan(1,3,9...*)[(1..3)]menjadi(3 9 27)Bahkan bisa dinest, jadi bentuk seperti
(1,2,4...*)[(1,2,4...*)[1,2,3]]juga memungkinkanIni terasa seperti memilih beberapa fitur Raku yang menarik untuk dibahas
Menurut saya, fitur Raku yang paling penting adalah antarmuka baris perintah dan grammar
Dukungan antarmuka baris perintah adalah fitur yang umum, misalnya ada implementasi dan contoh adopsi
docopt. Tetapi di Raku, fitur ini sudah bawaan dan enak dipakaiSebaliknya, grammar adalah fitur yang jarang karena bahasa pemrograman menyediakan grammar sebagai komponen kelas satu, dan memungkinkan grammar dibuat serta dikombinasikan dengan pemrograman berorientasi objek
Saya sudah mengikuti proyek ini selama beberapa tahun dan memang menarik, tetapi sangat disayangkan karena Perl 6 tampaknya terlalu tersesat dalam perjalanan ke negeri cermin ini