El reto
En este desafío, especifica un idioma de origen S
y un idioma de destino T
. Su tarea es escribir el siguiente programa P
en el idioma S
. Si se proporciona un programa válido Q
en el idioma T
como entrada P
, generará un programa válido R
en el idioma T
que no recibe entradas y salidas Q(R)
, es decir, el programa Q
aplicado al código fuente de R
. Además , debe presentar en su respuesta un programa de ejemplo no trivial Q
(cuanto más interesante, mejor, aunque no obtenga puntos por esto), el programa resultante R
y la salida de R
. Este es el código de golf, por lo que el código más corto para P
victorias.
En otras palabras, este es un desafío sobre escribir un "constructor universal de quines" que pueda crear tipos arbitrarios de quines generalizadas.
Aclaraciones
- Sus idiomas de origen y destino pueden ser idénticos.
- El programa
P
debe tomar una cadena como entrada (desde STDIN o equivalente), y generar una cadena (hacia STDOUT o equivalente), como debería hacerlo cada programa de salidaR
. - Los programas de entrada
Q
también deben transformar una cadena en otra cadena, pero su forma es más flexible: pueden ser funciones de cadena a cadena, fragmentos de código que modifican una variable con un nombre determinado, fragmentos que modifican la pila de datos si su idioma de destino tiene uno, etc. También puede restringir aún más la forma de losQ
's indicando que, por ejemplo, no pueden contener ningún comentario. Sin embargo, debe ser capaz de implementar cualquier función de cadena a cadena computable como un programa de entradaQ
, y debe indicar explícitamente cómo funcionan y qué restricciones adicionales les impone. - El programa de salida
R
realmente debería ser una quine (generalizada), por lo que no debe leer ninguna entrada (entrada del usuario, archivos, etc.) a menosQ
que lo haga. - Las lagunas estándar no están permitidas.
Un ejemplo
Supongamos que elijo Python como mi idioma de origen y Haskell como mi idioma de destino, y además necesito que el programa de entrada sea una definición de una línea de una String -> String
función llamada f
. Si doy el programa de inversión de cadenas
f x = reverse x
como entrada a mi programa Python P
, generará el código fuente de otro programa Haskell R
. Este programa imprime en STDOUT el código fuente de R
, pero se invierte. Si P
se le da la función de identidad
f x = x
Como entrada, el programa de salida R
es una quine.
fuente
Haskell expresiones → Haskell expresiones, 41 bytes
Pruébalo en línea!
Cómo funciona
P $ "Q"
=((++)<*>show).('(':).(++")$(++)<*>show$") $ "Q"
construcciones"R"
por(++")$(++)<*>show$")
: agregando la cadena")$(++)<*>show$"
,('(':)
: anteponer el personaje'('
, y(++)<*>show
(=\x->x++show x
): anexando una versión citada de eso,resultando en
"R"
="(Q)$(++)<*>show$\"(Q)$(++)<*>show$\""
.R
=(Q)$(++)<*>show$"(Q)$(++)<*>show$"
trabaja por"(Q)$(++)<*>show$"
,(++)<*>show
: agregando una versión citada de eso,Q
a eso,resultando en
Q "(Q)$(++)<*>show$\"(Q)$(++)<*>show$\""
=Q "R"
.(Los parens alrededor
Q
son necesarios porqueQ
pueden contener$
tan fácilmente como loR
hace, y$
desafortunadamente son correctos asociativos).Manifestación
fuente
$
necesita los paréntesis, pero también se arrastralet
,do
o expresiones lambda.let
/if
/case
/do
si no los emito yo mismo. Quizás sea mejor que no tuviera que hacerlo.Fuente = Destino = JavaScript, 66
Suposiciones para Q:
Q
debe ser una función anónima JavaScript de cadena a cadena.Ejemplos:
function(s) { return s.split('').reverse().join(''); }
En este caso,
P(Q)
(oR
) será:,function a(){console.log(function(s) { return s.split('').reverse().join(''); }(a+'a()'))}a()
y al ejecutarlo, obtendremos:)(a}))')(a'+a(} ;)''(nioj.)(esrever.)''(tilps.s nruter { )s(noitcnuf(gol.elosnoc{)(a noitcnuf
que es exactamente lo mismo queQ(R)
.function(s) { return s; }
en este caso,
P(Q)
(oR
) será:function a(){console.log(function(s) { return s; }(a+'a()'))}a()
que es una Quine de JavaScript . No hace falta decirQ(R)
que será lo mismo, ya que Q es la función de identidad.Algunas notas:
STDIN en JavaScript es tradicionalmente
prompt()
, sin embargo, me permití abstenerme de la tradición dealert()
STDOUT, para facilitar el proceso de ejecución de salida como un programa utilizando copiar y pegar. (Me doy cuenta de que puedo guardar hasta 12 caracteres al cambiar aalert()
).También puedo hacer las cosas mucho más cortas en ES6, pero quiero quedarme con JavaScript nativo por ahora. Estoy considerando enviar una respuesta S = Scala, T = ECMA6 en el futuro, solo por la experiencia.
También me doy cuenta de que JavaScript casi nunca puede vencer a CJam en code-golf , ¡pero tuve que aceptar este desafío! Fue hosco y divertido.
fuente
Jalea → 7 , 9 bytes
Pruébalo en línea!
Q es una función 7 (es decir, que no se ve más allá del elemento de la pila superior, y hace E / S a través de la pila), y se proporciona como un argumento de línea de comandos.
Explicación
El programa 7
El constructor universal de quine en 7 que uso aquí es:
Lo primero a tener en cuenta es que el 7 principal es el equivalente del espacio en blanco inicial y no tiene ningún efecto en el programa. La única razón por la que existe es para obedecer las reglas de PPCG contra las quines literales (está codificado por el segundo
1
en el programa en lugar de por sí mismo).El resto del programa es un elemento de pila único (tiene
7
s y6
s equilibrados ), que hace lo siguiente cuando se ejecuta:En otras palabras, este elemento de la pila es un programa que imprime la parte superior de la pila, con el
7
antepuesto, en formato de salida 7 (que significa "imprimir literalmente, usando la misma codificación que el código fuente", y por lo tanto es claramente la mejor codificación para quines). Es bastante afortunado aquí que podamos reutilizar el literal7
para dos propósitos (el formato de salida y el espacio en blanco inicial). Claramente, al insertar algo justo antes del final3
, podemos generar una función de7
+ la entrada, en lugar de simplemente generar7
y Entrada directa.¿Cómo llega este elemento de pila a su propio código fuente? Bueno, cuando se alcanza el final del programa, 7
eval
s es el elemento de la pila superior de forma predeterminada. Sin embargo, en realidad no se extrae de la pila en el proceso, por lo que el elemento literal de pila que seeval
llevó todavía está allí. (En otras palabras, el programa no está leyendo su propia fuente, como lo demuestra el hecho de que no puede ver7
al inicio del programa, que es un separador de elementos de pila en lugar de ser parte de un literal, sino que consiste principalmente en un literal que obtieneeval
dirige por defecto).El programa de gelatina
Este es quizás uno de los programas Jelly menos similares a Jelly que he escrito; se compone de tres nilads (
“ṚƓ^ṾṂ’
,³
,3
), que son sólo de salida en secuencia porque no se realizan operaciones en ellos. El3
es bastante obvio, solo es una constante entera. También³
es simple si conoce a Jelly: es la notación explícita de Jelly para el primer argumento de línea de comandos (que es donde Jelly normalmente toma su entrada). El resto del programa Jelly representa la mayor parte de mi constructor de quine universal 7: explotando el hecho de que todos los comandos en 7 pueden representarse usando dígitos ASCII, podemos interpretar717162234430
no como una serie de comandos, o incluso como un número octal (como lo es conceptualmente), sino como un número decimal, lo que significa que no necesitamos ningún formato especial para la salida. Ese número decimal se convierte“ṚƓ^ṾṂ’
en la notación entera comprimida de Jelly.Ejemplo
Si damos
24053
como programa Q, obtendremos el siguiente resultado:Pruébalo en línea!
2405
concatena el elemento superior de la pila consigo mismo:(El último paso puede parecer un poco confuso; lo que sucede es que escapar de un elemento de la pila convierte cada comando en él de "ejecutar este comando" a "agregar este comando a la parte superior de la pila", por lo que cada comando se agrega al original elemento de pila superior a medida que se ejecuta).
Como tal, ejecutar el programa resultante R nos da dos copias de R:
fuente
CJam → CJam, 13 bytes
Pruébalo en línea!
La entrada
Q
debe ser un fragmento de código que modifique la única cadena en la pila.Q
se lee de stdin.Ejemplo
Entrada:
Agrega un espacio entre cada dos caracteres e invierte la cadena.
Salida:
Salida de la quine generalizada:
Explicación
Primero evalúa el quine, para que podamos obtener su representación de cadena sin comillas dobles innecesarias. Luego reemplace la carga útil con la entrada.
Podría ser
{`"_~"+ }_~7qt
donde el espacio es el marcador de posición de la carga útil. Pero cambiar la carga útil a7
ahorra un byte.fuente
Carbón → Perl (5),
2933 bytesPruébalo en línea!
El programa Q de Perl debería devolver un fragmento que toma la entrada como una cadena a su lado derecho y proporciona salida en la variable
$_
. (Las funciones Perl arbitrarias se pueden convertir a este formulario envolviéndolas comosub x {…}; $_=x
. Sin embargo, en la mayoría de los casos, la sintaxis de Perl significa que no se requiere envoltura).Explicación
El perl
Así es como se ve el constructor universal de Perl quine:
(En la mayoría de los casos, desearía reducir esto
$_=q(say…"\$_=q($_);eval");eval
, pero no estoy seguro de que pueda incluir código arbitrario de Perl…
allí).En otras palabras, tenemos un contenedor externo
$_=q(…);eval
que asigna una cadena$_
y luego la evalúa. Dentro de la envoltura hay"\$_=q($_);eval"
, es decir, una reconstrucción de la envoltura junto con su contenido mediante el uso del valor que almacenamos$_
, más el código Q especificado por el usuario, másprint
para imprimir la salida. (Desafortunadamente no podemos usarsay
; agrega una nueva línea, y eso es relevante en quines).El carboncillo
El "punto" de esta respuesta fue producir quines generalizados en Perl, por lo que una vez que tuve una estrategia de golf para hacerlo (una que he usado en muchas otras respuestas), llegó el momento de escribir el programa P, que básicamente solo sustituye una cadena en una plantilla. Lo que quería aquí era un lenguaje que fuera bueno para imprimir cadenas constantes (idealmente comprimiéndolas un poco) e interpolar la entrada del usuario en ellas.
Después de probar algunos, me decidí por el carbón, que nunca había usado antes (y que realmente podría hacer con algo de documentación); Está diseñado para el arte ASCII, pero también es capaz de escribir cadenas en una dimensión. Los caracteres ASCII se imprimen literalmente en Carbón, lo que significa que la impresión de cadenas constantes no requiere repeticiones, y podemos usar el
S
comando para interpolar una cadena tomada de la entrada del usuario en el programa.Sin embargo, es posible ir (ligeramente) más corto. El constructor de quine universal Perl contiene dos secciones repetidas bastante largas. Por lo tanto, podemos usar el
A
comando para asignarlos a variables (por ejemplo,A…α
asigna a la variableα
), y simplemente interpolar las variables en la cadena que estamos imprimiendo utilizando sus nombres. Eso ahorra unos pocos bytes con solo escribir la cadena literalmente.Desafortunadamente, Charcoal también agrega una nueva línea al programa, pero eso no es un gran problema; simplemente cuesta dos bytes para
\n
que agregar esa nueva línea a la entrada de Q también.Ejemplo
Si damos la entrada
$_=reverse
(que invierte una cadena), obtenemos la siguiente salida:Pruébalo en línea!
que es un quine-like que imprime su fuente al revés, como se esperaba.
fuente
Jalea → Subcarga , 15 bytes
Pruébalo en línea!
Toma la entrada de la función de subcarga Q como un argumento similar a un comando. Q debe tomar la entrada de la pila y enviar la salida a la pila, sin intentar inspeccionar los elementos más profundos de la pila (ya que no existirán).
Explicación
La subcarga
El constructor de quine universal de baja carga utilizado aquí es:
La mayor parte del programa es un solo literal. Seguimos eso
:^
, que lo copia, luego evalúa una copia (dejando la otra copia en la pila).Cuando el literal comienza a evaluar, ejecutamos
a
(escape, que lo devuelve a la misma forma que el programa original A) y(:^)*
(que se adjunta:^
), reconstruyendo así el código fuente de todo el programa. Luego podemos ejecutar la función Q para transformar esto de manera arbitraria e imprimir el resultado conS
.La gelatina
Esta vez no puedo usar el carbón porque un intérprete de validación de Underload se bloquea al final del programa si el programa termina con una nueva línea. (Algunos intérpretes de baja carga, como el que está en TIO, no aplican esta regla, pero quería ser adecuadamente portátil). Desafortunadamente, Charcoal agrega naturalmente nuevas líneas finales a su salida. En cambio, usé Jelly, que es casi tan conciso en casos simples como este; el programa consiste en una lista literal con dos elementos (
““”
), y los une en la entrada (j
), interpolando así la entrada del usuario en el programa.Ejemplo
Usando la entrada
:S^
(imprima una copia, luego evalúe el original), obtenemos el siguiente programa Underload:Pruébalo en línea!
Esto se imprime infinitamente muchas veces, de una manera bastante interesante: después de realizar el comportamiento normal de quine, se ejecuta
eval
en una copia de lo que genera. Eso hace que todo el programa reconstruido vuelva a ejecutarse, indefinidamente (Underload es recursivo). Encargarse de uno mismo y hacer un eneval
realidad es la única forma de hacer un bucle infinito en Underload.fuente
RProgN 2 , 11 bytes
Explicación del programa
Quine Explination
La quine que se produce es simple, pero utiliza la funcionalidad de controladores de funciones inigualables en RProgN2 para crear una quine corta y dulce, llamada quine "Looping". Es un concepto sorprendentemente similar a una <> <quine.
Por supuesto, debido a la estructura de este quine, todo lo que no sea un verdadero no-ops (que no se encadena) puede colocarse después de la función concatenate, y
Algunas quines
{`{.i}{
: Salidas{}i.{`{
.i
es solo la función "inversa", por lo que este programa se genera invertido.{`{.S§.}{
: Salidas..S`{{{}§
.S
convierte la cadena en una pila de caracteres,§
clasifica la pila lexográficamente, luego la.
une de nuevo y se ordena.Pruébalo en línea!
fuente