Definición de nuevos operadores integrados
El intérprete estándar de GolfScript tiene una característica raramente utilizada que permite el código Ruby interpolado en literales de cadena entre comillas dobles.
Una razón por la cual esta característica no se usa con más frecuencia es que, incómodamente, el código interpolado se ejecuta en tiempo de compilación , y el intérprete de GolfScript almacena en caché la salida para que el mismo literal de cadena siempre produzca el mismo valor, incluso dentro cadena eval.
Sin embargo, una cosa para la que resulta útil esta característica es definir nuevos operadores de GolfScript implementados en el código Ruby. Por ejemplo, aquí se explica cómo definir un nuevo operador de suma binaria que funcione igual que el +
operador integrado estándar :
"#{var'add','gpush a+b'.cc2}";
Realmente no importa dónde pones la definición en tu código; el nuevo operador se define tan pronto como se analiza la cadena entre comillas dobles que contiene el código Ruby. El add
operador definido anteriormente funciona exactamente como el +
operador incorporado , y se puede usar exactamente de la misma manera:
1 2 add # evaluates to 3
"foo" "bar" add # evaluates to "foobar"
Por supuesto, definir un nuevo operador de adición es bastante inútil, a menos que haya hecho algo tonto como borrar el +
operador incorporado . Pero puede usar el mismo truco para definir nuevos operadores que hacen cosas que Golfscript no puede hacer (fácilmente) de forma nativa, como, por ejemplo, barajar uniformemente una matriz:
"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";
10,shuf # evaluates to 0,1,2,...,9 in random order
o imprimir el contenido de toda la pila:
"#{var'debug','puts Garray.new($stack).ginspect'.cc}";
4,) ["foo" debug # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched
o entrada interactiva:
"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";
]; { "> " print gets ~ ]p 1 } do # simple GolfScript REPL
o incluso acceso 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
Por supuesto, una implementación algo más golfista (¡y más riesgosa!) De este último sería, por ejemplo:
"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";
Si bien no es particularmente golfoso en sí mismo, esto le permite ampliar las capacidades de GolfScript más allá de lo que proporcionan los comandos integrados.
¿Como funciona?
La referencia autorizada sobre cómo definir nuevos operadores de GolfScript de esta manera es, por supuesto, el código fuente para el intérprete . Dicho esto, aquí hay algunos consejos rápidos:
Para definir un nuevo operador name
que ejecute el código Ruby code
, use:
var'name','code'.cc
Dentro del código, úselo gpop
para leer un valor de la pila y gpush
para volver a introducir uno. También puede acceder a la pila directamente a través de la matriz $stack
. Por ejemplo, para empujar tanto a
y b
en la pila, es Golfier hacer $stack<<a<<b
que gpush a;gpush b
.
- Las posiciones de los
[
marcadores de inicio de la matriz se almacenan en la $lb
matriz. La gpop
función se encarga de ajustar estos marcadores hacia abajo si la pila se contrae por debajo de su posición, pero la manipulación de la $stack
matriz no lo hace directamente.
El .cc
método de cadena que compila el código Ruby en una cadena en un operador de GolfScript es solo una envoltura conveniente Gblock.new()
. También tiene las variantes .cc1
, .cc2
y .cc3
eso hace que el operador extraiga automáticamente 1, 2 o 3 argumentos de la pila y los asigne a las variables a
, b
y c
. También hay un .order
método que funciona como .cc2
, excepto que clasifica automáticamente los argumentos por tipo de prioridad .
Todos los valores en la pila GolfScript son (y deben ser!) Los objetos de tipo Gint
, Garray
, Gstring
o Gblock
. Se puede acceder al entero nativo subyacente o matriz, donde sea necesario, a través del .val
método.
- Sin embargo, tenga en cuenta que
Gstring.val
devuelve una matriz de Gint
s! Para convertir una Gstring
cadena de Ruby en nativa, invoque .to_s
en su lugar (o úsela en un contexto que lo haga automáticamente, como la interpolación de cadenas). Invocar .to_gs
cualquier valor GS lo convierte en a Gstring
, por lo que cualquier valor GS puede ser encadenado .to_gs.to_s
.
La gpush
función no ajusta automáticamente los números, cadenas o matrices nativos de Ruby en los tipos GS correspondientes, por lo que a menudo tendrá que hacerlo usted mismo llamando explícitamente, por ejemplo Gstring.new()
. Si inserta algo que no sea uno de los tipos de valor GS en la pila, es probable que se bloquee cualquier código que luego intente manipularlo.
Los tipos de valor GS también tienen un .factory
método que llama al constructor del tipo, que puede ser útil, por ejemplo, para reenvolver matrices / cadenas después de manipular sus contenidos. Todos los tipos también tienen un .coerce
método que realiza la coerción de tipos : a.coerce(b)
devuelve un par que contiene a
y b
coaccionado al mismo tipo.
... x
en... [x]
? Lo mejor que puedo ver es[.;]
.