Xác định toán tử tích hợp mới
Trình thông dịch GolfScript tiêu chuẩn có một tính năng hiếm khi được sử dụng cho phép mã Ruby được nội suy theo hai chuỗi ký tự được trích dẫn.
Một lý do tại sao tính năng này không được sử dụng phổ biến hơn là, một cách vụng về, mã nội suy được thực thi tại thời gian biên dịch và đầu ra được trình thông dịch GolfScript lưu vào bộ đệm để cùng một chuỗi ký tự sau đó sẽ luôn mang lại cùng một giá trị, ngay cả bên trong chuỗi eval.
Tuy nhiên, một điều mà tính năng này hóa ra là tốt cho việc xác định các toán tử GolfScript mới được triển khai theo mã Ruby. Ví dụ: đây là cách xác định toán tử cộng nhị phân mới hoạt động giống như +
toán tử tích hợp chuẩn:
"#{var'add','gpush a+b'.cc2}";
Nó không thực sự quan trọng khi bạn đặt định nghĩa trong mã của bạn; toán tử mới được định nghĩa ngay khi chuỗi trích dẫn kép chứa mã Ruby được phân tích cú pháp. Các add
nhà điều hành được xác định trên công trình chính xác như được xây dựng trong +
điều hành, và có thể được sử dụng trong một cách chính xác theo cùng một cách:
1 2 add # evaluates to 3
"foo" "bar" add # evaluates to "foobar"
Tất nhiên, việc xác định toán tử bổ sung mới là khá vô ích, trừ khi bạn đã làm điều gì đó ngớ ngẩn như xóa +
toán tử tích hợp . Nhưng bạn có thể sử dụng cùng một mẹo để xác định các toán tử mới thực hiện những điều mà Golfscript không thể (dễ dàng) thực hiện một cách tự nhiên như, giả sử, xáo trộn đồng đều một mảng:
"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";
10,shuf # evaluates to 0,1,2,...,9 in random order
hoặc in nội dung của toàn bộ ngăn xếp:
"#{var'debug','puts Garray.new($stack).ginspect'.cc}";
4,) ["foo" debug # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched
hoặc đầu vào tương tác:
"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";
]; { "> " print gets ~ ]p 1 } do # simple GolfScript REPL
hoặc thậm chí truy cập 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
Tất nhiên, việc triển khai phần sau golfer (và rủi ro hơn!) Sẽ là:
"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";
Mặc dù bản thân nó không đặc biệt chơi gôn, nhưng điều này cho phép bạn mở rộng khả năng của GolfScript ngoài những gì các lệnh tích hợp cung cấp.
Làm thế nào nó hoạt động?
Tất nhiên, tài liệu tham khảo có thẩm quyền về cách xác định các toán tử GolfScript mới theo cách này là mã nguồn cho trình thông dịch . Điều đó nói rằng, đây là một vài mẹo nhanh:
Để xác định toán tử mới name
chạy mã Ruby code
, hãy sử dụng:
var'name','code'.cc
Bên trong mã, sử dụng gpop
để đọc một giá trị khỏi ngăn xếp và gpush
đẩy một giá trị trở lại. Bạn cũng có thể truy cập ngăn xếp trực tiếp qua mảng $stack
. Ví dụ, để đẩy cả hai a
và b
lên ngăn xếp, việc chơi gôn sẽ $stack<<a<<b
tốt hơn gpush a;gpush b
.
- Các vị trí của các
[
dấu bắt đầu mảng được lưu trữ trong $lb
mảng. Các gpop
chức năng chăm sóc điều chỉnh các điểm đánh dấu xuống nếu stack co lại xuống đến vị trí của họ, nhưng thao tác $stack
mảng trực tiếp thì không.
Các .cc
phương pháp chuỗi mà biên dịch mã Ruby trong một chuỗi thành một nhà điều hành GolfScript chỉ là một wrapper tiện xung quanh Gblock.new()
. Nó cũng có các biến thể .cc1
, .cc2
và .cc3
khiến các nhà điều hành tự động bật 1, 2 hoặc 3 đối số ra khỏi stack và gán chúng cho các biến a
, b
và c
. Ngoài ra còn có một .order
phương thức hoạt động như thế .cc2
, ngoại trừ việc nó tự động sắp xếp các đối số theo mức độ ưu tiên .
Tất cả các giá trị trên stack GolfScript là (và nên) đối tượng của loại hình Gint
, Garray
, Gstring
hoặc Gblock
. Số nguyên hoặc mảng gốc bên dưới, nếu cần, có thể được truy cập thông qua .val
phương thức.
- Tuy nhiên, lưu ý rằng
Gstring.val
trả về một mảng của Gint
s! Để biến một Gstring
chuỗi thành chuỗi Ruby gốc, .to_s
thay vào đó , hãy gọi nó (hoặc sử dụng nó trong ngữ cảnh tự động thực hiện, như nội suy chuỗi). Gọi .to_gs
bất kỳ giá trị GS nào cũng biến nó thành một Gstring
, vì vậy mọi giá trị GS đều có thể được xâu chuỗi bằng .to_gs.to_s
.
Các gpush
chức năng không tự động quấn số của Ruby tự nhiên, chuỗi hoặc mảng thành các loại GS tương ứng, vì vậy bạn sẽ thường xuyên phải làm điều đó cho mình bằng cách gọi một cách rõ ràng ví dụ Gstring.new()
. Nếu bạn đẩy bất cứ thứ gì ngoài một trong các loại giá trị GS lên ngăn xếp, bất kỳ mã nào sau đó cố gắng thao tác nó đều có khả năng bị sập.
Các loại giá trị GS cũng có một .factory
phương thức gọi hàm tạo của kiểu, có thể hữu ích, ví dụ như để sắp xếp lại các mảng / chuỗi sau khi thao tác với nội dung của chúng. Tất cả các loại cũng có một .coerce
phương thức thực hiện cưỡng chế kiểu : a.coerce(b)
trả về một cặp chứa a
và b
ép buộc cùng loại.
... x
thành... [x]
? Điều tốt nhất tôi có thể thấy là[.;]
.