Un políglota es un programa que se puede ejecutar en 2 o más lenguajes de programación diferentes.
¿Qué consejos generales tiene para hacer políglotas o elegir idiomas que sean fáciles de escribir políglotas para una tarea específica?
Publique los consejos que podrían aplicarse en la mayoría de las situaciones. Es decir, no deberían funcionar solo en políglotas de dos idiomas específicos. (Simplemente puede publicar una respuesta a una pregunta de políglotas si tiene una sugerencia demasiado específica). Pero puede introducir características de un lenguaje que facilite el trabajo con muchos idiomas, o sea fácil de agregar a cualquier políglota existente.
Por favor, publique un consejo por respuesta. Y siéntase libre de sugerir editar si un consejo específico de idioma también se aplica a otro idioma.
Divide y conquistaras
Cuando escribe un políglota en una gran cantidad de idiomas, no necesariamente podrá separar todos los flujos de control del idioma entre sí inmediatamente. Por lo tanto, necesitará "verdadero políglota" de algunos de los idiomas durante un período de tiempo, permitiendo que se ejecute el mismo código en cada uno de ellos. Hay dos reglas principales a tener en cuenta al hacer esto:
El flujo de control en cualquiera de los dos idiomas debe ser muy similar o muy diferente . Intentar manejar una gran cantidad de flujos de control intercalados es una receta para confundirse y hace que su programa sea difícil de modificar. En cambio, debe limitar la cantidad de trabajo que tiene que hacer asegurándose de que todos los programas que están en el mismo lugar estén allí por la misma razón y puedan ejecutarse en paralelo durante el tiempo que necesite. Mientras tanto, si un idioma es muy diferente de los demás, desea que su ejecución se mueva a una ubicación muy diferente lo antes posible, para que no tenga que intentar que su código se ajuste a dos modelos sintácticos diferentes a la vez.
Busque oportunidades para dividir un idioma, o un grupo de idiomas similares, separados unos de otros. Trabajar desde grupos más grandes hasta grupos más pequeños. Una vez que tenga un grupo de idiomas similares, todos en un determinado punto del programa, deberá dividirlos en algún momento. Al comienzo del programa, es posible que, por ejemplo, desee dividir los idiomas que se usan
#
como marcador de comentarios de los idiomas que usan algún otro marcador de comentarios. Más adelante, quizás tenga un punto en el que todos los idiomas usan laf(x)
sintaxis para las llamadas a funciones, separan los comandos con punto y coma y tienen similitudes sintácticas similares. En ese momento, podría usar algo mucho más específico del idioma para dividirlos, por ejemplo, el hecho de que Ruby y Perl no procesan secuencias de escape en''
cadenas, pero Python y JavaScript sí.En general, el flujo lógico de su programa debe terminar como un árbol, dividiéndose repetidamente en grupos de idiomas que son más similares entre sí. Esto pone la mayor parte de la dificultad en escribir el políglota justo al comienzo, antes de la primera división. A medida que el flujo de control se ramifica más y más, y los idiomas que se ejecutan en un punto dado se vuelven cada vez más similares, su tarea se vuelve más fácil porque puede usar una sintaxis más avanzada sin causar que los idiomas involucrados tengan un error de sintaxis.
Un buen ejemplo es el conjunto {JavaScript, Ruby, Perl, Python 3}; Todos estos idiomas aceptan llamadas a funciones con paréntesis y pueden separar las declaraciones con punto y coma. Todos ellos también admiten una
eval
declaración, que efectivamente le permite controlar el flujo de forma portátil. (Perl es el mejor de estos idiomas para separarse temprano del grupo, porque tiene una sintaxis diferente para las variables de los otros).fuente
Ocultar código dentro de literales de cadena
En la mayoría de los idiomas, un literal de cadena por sí solo no hace nada o hace algo que se puede revertir fácilmente (como empujar la cadena a la pila). La sintaxis literal de cadenas también está relativamente no estandarizada, especialmente para las sintaxis alternativas que muchos lenguajes usan para manejar cadenas con líneas nuevas incrustadas; por ejemplo, Python tiene
""" ... """
, Perl tieneq( ... )
y Lua tiene[[ ... ]]
.Hay dos usos principales de estos. Una es permitirle intercalar secciones destinadas a diferentes idiomas al comenzar una cadena al final de la primera sección de un idioma y reanudarla al comienzo de la segunda: debería ser bastante fácil evitar cerrar accidentalmente la cadena debido a la variedad de delimitadores de cadena entre diferentes idiomas. El otro es que muchos delimitadores de cadena son significativos como un comando en otros idiomas (a menudo más que los marcadores de comentarios), por lo que puede hacer algo como
x = [[4] ]
, que es una asignación inofensiva en idiomas que usan notación JSON para listas, pero que comienza una cadena en Lua (y por lo tanto le permite dividir el código Lua del resto, dado que efectivamente "salta" al siguiente]]
).fuente
Finalizando el programa
Puede finalizar el programa abruptamente en un idioma para que ignore el código en otro idioma.
Básicamente, este formato se puede usar
donde
end_program_in_languageN
está el comando para finalizar el programa.Por ejemplo, en mi respuesta en ¿Qué traerá para el Día de Acción de Gracias? , Terminé el programa en Dip, y luego escribí código para otro idioma, V, para que el intérprete de Dip lo ignorara.
Pero entonces, no todos los idiomas tienen un comando que pueda finalizar el programa así como así. Sin embargo, si dicho lenguaje tiene la característica, debe usarse con prudencia.
Como sugirió @LuisMendo, puede crear un error (si está permitido) para finalizar el programa si el idioma aún no tiene un "programa final" incorporado.
fuente
Variable o código dentro de literales de cadena
Los literales de cadena entre comillas dobles son en su mayoría inofensivos en muchos idiomas. Pero en algunos idiomas también podrían contener código.
En Bash, puede usar
`...`
(no termina el programa):En Tcl, puedes usar
[...]
:En PHP, puede usar
${...}
(esto genera un error en Bash, por lo que debe aparecer después del código Bash):En Ruby, puedes usar
#{...}
:Puede haber también otros.
Estas gramáticas no son compatibles. Eso significa que puede colocar todo el código de estos idiomas en una cadena en una ubicación inofensiva. Y simplemente ignorará el código no reconocido en otros idiomas y los interpretará como contenido de cadena.
En muchos casos, también podría comentar fácilmente un carácter de comillas dobles allí y hacer un políglota más tradicional.
fuente
Alias Variable
Este es probablemente uno de los trucos más importantes (IMO) más simples de usar, especialmente porque puede llegar a tantos idiomas.
Ejemplo:
Esto funcionará no solo en Javascript, sino también en Python, Ruby, etc. Más ejemplos más adelante cuando pienso en algunos otros. Por supuesto, las sugerencias de comentarios / ediciones de publicaciones son bienvenidas.
fuente
alert
queprint
en Python (3 solamente), porque la sintaxis de comentario de JS,//
, puede ser fácilmente trabajado en un programa Python, mientras que Python#
no se puede trabajar en JS.#
comentarios basados enEste consejo es un subconjunto de símbolos de comentario de explotación y citas en bloque en al menos un idioma
Al crear políglotas con muchos idiomas, especialmente lenguajes listos para producción en lugar de esolangs, puede ser útil observar los idiomas que se usan
#
en comentarios de bloque o de una sola línea.#
, y hay mucha variedad en los caracteres que siguen a#
.#
comentario de línea, lo que significa que algo que podría comenzar un comentario de bloque en un idioma es solo un comentario ordinario en otro, lo que facilita su adaptación.Aquí hay una lista de resumen rápido de idiomas que se usan
#
en un comentario de bloque (no exhaustivo):Para más ejemplos, vea el Código de Rosetta .
Aquí hay un ejemplo rápido y fácil, como demostración:
fuente
#- ... -#
.Discrepancias de operador aritmético
Para lenguajes similares o políglotas simples, a veces es útil buscar diferencias en cómo los lenguajes realizan la aritmética. Esto se debe a que la mayoría de los lenguajes (no esotéricos) tienen operadores aritméticos infijados y la aritmética puede ser una forma rápida y fácil de introducir una diferencia.
Por ejemplo:
^
es XOR bit a bit en algunos idiomas y exponenciación en otros/
es la división de enteros en algunos idiomas y la división de coma flotante en otros-1/2
está-1
en algunos idiomas (redondear hacia abajo) y0
en otros (redondear a cero)-1%2
está-1
en algunos idiomas y1
en otros--x
es un no-op en algunos idiomas (doble negación) y pre-decrement en otros1/0
da infinito en algunos idiomas y errores en otros1<<64
da 0 en algunos idiomas (desbordamiento) y36893488147419103232
en otrosfuente
x=1;["JS","Python"][--x]
, que devuelve el nombre del idioma en el que se ejecuta (entre JS y Python).Usa Brainfuck
Casi todas las implementaciones de BF arrojan caracteres que no lo son
+-<>[].,
, ¡lo que funciona a nuestro favor!BF es probablemente uno de los lenguajes más fáciles de trabajar en un políglota debido a esta característica, siempre que primero escriba la parte BF. Una vez que haya escrito su código BF, es solo cuestión de modelar cualquier otro código que tenga alrededor de la estructura BF.
Aquí hay un ejemplo realmente simple:
Esto prácticamente aumenta y produce salidas de código de código "para siempre" (dependiendo de la configuración del tiempo de ejecución). Ahora, si quisiera escribir un código aleatorio, por ejemplo, en JS, podría hacer:
Observe cómo se moldea el JS alrededor del BF.
Asegúrese de saber que esto funciona mejor si realmente está listo para comenzar con BF; es bastante más difícil comenzar con otro idioma e intentar incorporar BF.
fuente
[]
como sea necesario.x=>
cambia la celda, que en este caso no importa, pero solo quería decirUse idiomas en los que la mayoría de los caracteres no importan
Esta es una generalización del punto de Mama Fun Roll sobre BF . Un esolang que ignora la mayoría de los caracteres es muy útil en políglotas. También es útil: un esolang en el que un gran conjunto de caracteres son intercambiables. Algunos ejemplos:
()[]{}<>
. (a@
veces causa un error cuando el intérprete intenta analizarlo como el inicio de un indicador de depuración).fuente
@
error.exec('''...\t\n\40''')
Tenga cuidado con los comentarios de bloque anidados
A veces, varios idiomas usarán la misma sintaxis para los comentarios de bloque, que a menudo es un factor decisivo para crear un políglota con los dos idiomas. Sin embargo, muy ocasionalmente, uno de los idiomas permitirá comentarios de bloque anidados, que se pueden abusar para crear rutas de código separadas.
Por ejemplo, considere este políglota:
Nim y Lily usan
#[
y]#
para comenzar y finalizar comentarios de bloque, pero solo Nim permite comentarios de bloque anidados.Lily considera que el segundo
#[
es parte del comentario de bloque singular y el primero]#
como que termina el comentario de bloque. (La#
siguiente declaración impresa de Lily es un comentario de línea que oculta el código de Nim).Nim, alternativamente, lo ve
#[]#
como un comentario de bloque anidado (aunque vacío) yprint("Lily")#
como el comentario de bloque externo.fuente
No estoy seguro si esto cuenta, pero ...
Use una línea shebang para convertir todo en un
perl
programa válidoDe acuerdo con esta respuesta y la documentación de Perl, si pasa cualquier archivo que comience con una línea shebang
perl
, invoca el programa apropiado para ejecutarlo. Por ejemplo, estose ejecuta por el intérprete de Python si llama
perl filename.py
.fuente
perl
, no se convierte en un programa Perl.perl
"? Suena como un buen meme filosófico ...Llame a funciones inexistentes, luego salga mientras evalúa sus argumentos
Muchos lenguajes de programación son capaces de analizar un identificador arbitrario seguido de un par de paréntesis con expresiones dentro:
A veces, la forma del identificador en cuestión puede ser fija, debido a que es necesario dar el código a un idioma diferente que está utilizando. Al principio, eso podría parecer problemático si el identificador no corresponde a una función que realmente tiene el lenguaje.
Sin embargo, muchos lenguajes de programación evaluarán los argumentos de una función antes de verificar si la función en sí existe (por ejemplo, Lua) y, de todos modos, puede usar este tipo de construcción; todo lo que necesita es salir del programa en algún lugar dentro de los argumentos de la función.
Aquí hay un ejemplo, un políglota dc / Lua:
c2pq
es un programa de CC para imprimir 2 y salir; Lua ve esto como el nombre de una función, pero se puede evitar que Lua cometa un error al colocar un comando de salida en su argumento. La gran ventaja de esta construcción es que, a diferencia de una asignación (c2pq =
), no es automáticamente incompatible con los idiomas en los que los nombres de las variables comienzan con un sigilo; la sintaxis del nombre de la función es mucho más coherente en todos los idiomas que la sintaxis del nombre de la variable.fuente