Menentukan operator bawaan baru
Standar GolfScript interpreter memiliki jarang digunakan fitur yang yang memungkinkan kode Ruby interpolasi dalam string literal yang dikutip ganda.
Salah satu alasan mengapa fitur ini tidak lebih umum digunakan adalah bahwa, canggung, kode interpolasi dijalankan pada waktu kompilasi , dan output di-cache oleh interpreter GolfScript sehingga string literal yang sama akan selalu menghasilkan nilai yang sama, bahkan di dalam string eval.
Namun, satu hal fitur ini ternyata bagus untuk mendefinisikan operator GolfScript baru diimplementasikan dalam kode Ruby. Sebagai contoh, berikut ini cara mendefinisikan operator penjumlahan biner baru yang berfungsi seperti operator bawaan standar +
:
"#{var'add','gpush a+b'.cc2}";
Tidak masalah di mana Anda memasukkan definisi dalam kode Anda; operator baru akan ditentukan segera setelah string yang dikutip ganda berisi kode Ruby diuraikan. The add
Operator didefinisikan di atas karya persis seperti built-in +
operator, dan dapat digunakan dengan cara yang persis sama:
1 2 add # evaluates to 3
"foo" "bar" add # evaluates to "foobar"
Tentu saja, mendefinisikan operator tambahan baru sangat tidak berguna, kecuali Anda telah melakukan sesuatu yang konyol seperti menghapus +
operator bawaan . Tetapi Anda dapat menggunakan trik yang sama untuk mendefinisikan operator baru yang melakukan hal-hal yang tidak dapat (dengan mudah) dilakukan oleh Golfscript seperti, misalnya, menyeret array secara seragam:
"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";
10,shuf # evaluates to 0,1,2,...,9 in random order
atau mencetak isi seluruh tumpukan:
"#{var'debug','puts Garray.new($stack).ginspect'.cc}";
4,) ["foo" debug # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched
atau input interaktif:
"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";
]; { "> " print gets ~ ]p 1 } do # simple GolfScript REPL
atau bahkan akses web:
"#{
require 'net/http'
require 'uri'
var'get','gpush Gstring.new(Net::HTTP.get_response(URI.parse(a.to_s)).body)'.cc1
}";
"http://example.com" get
Tentu saja, implementasi yang lebih golf (dan lebih berisiko!) Dari yang terakhir akan misalnya:
"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";
Meskipun tidak terlalu bersifat golf, ini memungkinkan Anda memperluas kemampuan GolfScript melampaui apa yang disediakan perintah bawaan.
Bagaimana cara kerjanya?
Referensi otoritatif tentang cara mendefinisikan operator GolfScript baru dengan cara ini, tentu saja, kode sumber untuk penerjemah . Yang mengatakan, inilah beberapa tips cepat:
Untuk menetapkan operator baru name
yang menjalankan kode Ruby code
, gunakan:
var'name','code'.cc
Di dalam kode, gunakan gpop
untuk membaca nilai dari stack, dan gpush
untuk mendorongnya kembali. Anda juga dapat mengakses stack secara langsung melalui array $stack
. Misalnya, untuk mendorong kedua a
dan b
ke stack, itu Golfier untuk melakukan $stack<<a<<b
daripada gpush a;gpush b
.
- Posisi
[
penanda mulai array disimpan dalam $lb
array. The gpop
Fungsi mengurus menyesuaikan tanda tersebut turun jika tumpukan menyusut di bawah posisi mereka, tetapi memanipulasi $stack
array yang langsung tidak.
The .cc
Metode string yang mengkompilasi kode Ruby dalam string ke operator GolfScript hanya bungkus-toko di sekitar Gblock.new()
. Ini juga memiliki varian .cc1
, .cc2
dan .cc3
itu membuat operator secara otomatis mengeluarkan argumen 1, 2 atau 3 dari stack dan menetapkannya ke variabel a
, b
dan c
. Ada juga .order
metode yang berfungsi seperti itu .cc2
, kecuali bahwa itu secara otomatis mengurutkan argumen berdasarkan jenis prioritas .
Semua nilai-nilai pada stack GolfScript adalah (dan harus!) Objek dari jenis Gint
, Garray
, Gstring
atau Gblock
. Integer atau array asli yang mendasarinya, di mana diperlukan, dapat diakses melalui .val
metode.
- Namun, perhatikan bahwa
Gstring.val
mengembalikan array Gint
s! Untuk mengubah Gstring
menjadi string Ruby asli, panggil .to_s
saja (atau gunakan dalam konteks yang melakukannya secara otomatis, seperti interpolasi string). Memanggil .to_gs
nilai GS apa pun mengubahnya menjadi Gstring
, sehingga nilai GS apa pun dapat dirangkum dengan .to_gs.to_s
.
The gpush
Fungsi tidak auto-wrap nomor Ruby asli, string atau array ke dalam jenis GS yang sesuai, sehingga Anda akan sering harus melakukannya sendiri dengan secara eksplisit menyebut misalnya Gstring.new()
. Jika Anda mendorong apa pun selain salah satu dari tipe nilai GS ke tumpukan, kode apa pun yang kemudian mencoba untuk memanipulasinya kemungkinan akan mogok.
Tipe nilai GS juga memiliki .factory
metode yang memanggil konstruktor tipe tersebut, yang dapat berguna misalnya untuk menyusun ulang array / string setelah memanipulasi kontennya. Semua tipe juga memiliki .coerce
metode yang melakukan pemaksaan tipe : a.coerce(b)
mengembalikan pasangan yang mengandung a
dan b
dipaksa ke tipe yang sama.
... x
menjadi... [x]
? Yang terbaik yang bisa saya lihat adalah[.;]
.