El objetivo de este desafío es (eventualmente) generar todos los posibles programas de detención en el idioma que elija. Al principio esto puede sonar imposible, pero puede lograr esto con una elección muy cuidadosa de la orden de ejecución.
A continuación se muestra un diagrama ASCII para ilustrar esto. Deje que las columnas representen una numeración de cada programa posible (cada programa es un número finito de símbolos de un alfabeto finito). Deje que cada fila represente un paso singular en la ejecución de ese programa. An X
representa la ejecución realizada por ese programa en ese paso de tiempo.
step# p1 p2 p3 p4 p5 p6
1 X X X X X X
2 X X X X X
3 X X X X
4 X X X X
5 X X X
6 X X
7 X X
8 X X
9 X X
∞ X X
Como puede ver, los programas 2 y 4 no se detienen. Si los ejecutara uno a la vez, su controlador se quedaría atascado en el bucle infinito que es el programa 2 y nunca generaría los programas 3 y posteriores.
En su lugar, utiliza un enfoque de cola de milano . Las letras representan un posible orden de ejecución para los primeros 26 pasos. Los *
s son lugares donde ese programa se ha detenido y se emite. Los .
s son pasos que aún no se han ejecutado.
step# p1 p2 p3 p4 p5 p6
1 A C F J N R V
2 B E I M Q * Z
3 D H * P U
4 G L T Y
5 K O X
6 * S .
7 W .
8 . .
9 . .
∞ . .
Requisitos para el idioma de destino
El idioma de destino (el que se interpreta en paralelo) debe ser Turing completo. Aparte de eso, puede ser cualquier idioma que sea Turing completo, incluidos los subconjuntos Turing completos de idiomas mucho más grandes. También es libre de interpretar cosas como las reglas del sistema de etiquetas cíclicas. También puede crear un idioma para probar, siempre y cuando pueda mostrar por qué es Turing completo.
Como ejemplo, si elige probar brainfuck, lo mejor es probar solo el []-+<>
subconjunto, ya que la entrada no es compatible y la salida simplemente se descarta (ver más abajo).
Cuando se trata del programa "controlador" (que está jugando al golf), no hay requisitos especiales. Se aplican restricciones de idioma normales.
Cómo crear una lista infinita de programas
La mayoría de los lenguajes de programación se pueden representar como una serie de símbolos de un alfabeto finito. En este caso, es relativamente fácil enumerar una lista de todos los programas posibles en orden creciente. El alfabeto que use debe ser representativo de los requisitos del idioma de destino. En la mayoría de los casos, esto es ASCII imprimible. Si su idioma admite Unicode como una característica adicional, no debe probar todas las combinaciones posibles de caracteres Unicode, solo ASCII. Si su idioma solo usa []-+<>
, no pruebe las diversas combinaciones de caracteres ASCII de "comentario". Idiomas como APL tendrían sus propios alfabetos especiales.
Si su idioma se describe mejor de alguna manera no alfabética, como Fractran o Turing Machines, existen otros métodos igualmente válidos para generar una lista de todos los posibles programas válidos.
Interpretar una lista cada vez mayor de programas
La parte clave de este desafío es escribir un intérprete paralelo para una lista creciente de programas. Hay algunos pasos básicos para esto:
- Agregue un número finito de programas a la lista
- Interprete cada programa en la lista individualmente por un período de tiempo finito. Esto se puede lograr realizando un paso de instrucción para cada uno. Salva a todos los estados.
- Eliminar todos los programas de terminación / lanzamiento de errores de la lista
- Salida de los programas limpiamente detenidos *
- Agregue algunos programas más a la lista
- Simule cada programa a su vez, retomando la ejecución de programas antiguos donde se dejó
- Eliminar todos los programas de terminación / lanzamiento de errores de la lista
- Salida de los programas limpiamente detenidos *
- repetir
* Solo debe generar programas que se detengan limpiamente. Esto significa que no hubo errores de sintaxis o excepciones no detectadas lanzadas durante la ejecución. Los programas que solicitan información también deben finalizar sin generarlos. Si un programa produce resultados, no debe terminarlos, solo bótelos.
Más reglas
- No debe generar nuevos subprocesos para contener los programas probados, ya que esto descarga el trabajo de paralelización en el sistema operativo host / otro software.
- Editar: para cerrar posibles lagunas futuras, no se le permite
eval
(ni ninguna función relacionada) una parte del código del programa probado . Usted puedeeval
un bloque de código a partir del código del intérprete. (La respuesta BF-in-Python sigue siendo válida según estas reglas). - Esto es código golf
- El idioma en el que escribe su envío no necesita ser el mismo que el idioma que está probando / enviando.
- Debe suponer que su memoria disponible no tiene límites.
- Al probar la integridad de Turing, puede suponer que la entrada está codificada en el programa y que la salida se puede leer en el estado interno del programa.
- Si su programa se genera solo, probablemente sea incorrecto o políglota.
fuente
"If your program outputs itself, it is probably wrong or a polyglot."
Respuestas:
subleq OISC en Python,
317269 byteshttps://esolangs.org/wiki/Subleq
Un programa subleq es una lista extensible de enteros (p) y un puntero de instrucción (i). Esta variante subleq utiliza el direccionamiento relativo, que la página de discusión wiki sugiere que se requiere para asegurar la integridad con valores acotados. Cada tic,
p[i+p[i+1]]-=p[i+p[i]]
se realiza la operación , yi+=p[i+2]
si el resultado de la operación fue <= 0, de lo contrarioi+=3
. Si alguna vez es negativo, el programa se detiene.Esta implementación prueba cada programa cuyo estado inicial se compone de enteros no negativos de un dígito (0-9) con un puntero de instrucción inicial de 0.
La salida se invierte, por razones de golf. La especificación anterior podría reexpresarse a la inversa, pero no coincidiría con el código utilizado en la implementación, por lo que no lo he descrito de esa manera.
EDITAR: El primer programa que exhibe un crecimiento ilimitado simple es 14283, que disminuye el valor en la ubicación de memoria 6 y escribe un 0 explícito (en oposición al 0 implícito en cada celda) en la siguiente celda negativa, cada tres tics.
fuente
Etiqueta cíclica bit a bit en CJam,
98878477 bytesComo se trata de un bucle infinito, no puede probarlo directamente en el intérprete en línea. Sin embargo, aquí hay una versión alternativa que lee el número de iteraciones de STDIN para que juegues. Para probar el programa completo, necesitará el intérprete de Java .
BCT es una variante minimalista de Cyclic Tag Systems . Un programa está definido por dos cadenas binarias: una lista (cíclica) de instrucciones y un estado inicial. Para facilitarme la vida al imprimir los programas, he definido mi propia notación: cada una de las cadenas se da como una matriz de enteros estilo CJam, y todo el programa está rodeado
[[...]]
, por ejemploTambién estoy rechazando estados iniciales vacíos o listas de instrucciones vacías.
Las instrucciones en BCT se interpretan de la siguiente manera:
0
, elimine el bit inicial del estado actual.1
, lea otro bit de la lista de instrucciones, llame a esoX
. Si el bit inicial del estado actual es1
, agregueX
al estado actual, de lo contrario no haga nada.Si el estado actual alguna vez se vacía, el programa se detiene.
Los primeros pocos programas de detención son
Si desea ver más, consulte la versión en el intérprete en línea que he vinculado anteriormente.
Explicación
Así es como funciona el código. Para realizar un seguimiento de la combinación, siempre tendremos una matriz en la pila que contiene todos los programas. Cada programa es un par de una representación interna del código del programa (como
[[0 1 0] [1 0]]
), así como el estado actual del programa. Solo usaremos el último para hacer el cálculo, pero necesitaremos recordar el primero para imprimir el programa una vez que se detenga. Esta lista de programas simplemente se inicializa en una matriz vacía conL
.El resto del código es un bucle infinito
{...1}g
que primero agrega uno o más programas a esta lista y calcula un paso en cada programa. Los programas que se detienen se imprimen y eliminan de la lista.Estoy enumerando los programas contando un número binario. El primer dígito se elimina para garantizar que también podamos obtener todos los programas con ceros a la izquierda. Para cada representación binaria truncada, presiono un programa por cada posible división entre instrucciones y estado inicial. Por ejemplo, si el contador está actualmente en
42
, su representación binaria es101010
. Nos deshacemos del liderazgo1
y empujamos todas las divisiones no vacías:Como no queremos instrucciones o estados vacíos, comenzamos el contador en 4, lo que da
[[[0] [0]]]
. Esta enumeración se realiza mediante el siguiente código:El resto del código asigna un bloque a la lista de programas, que realiza un paso del cálculo de BCT en la segunda mitad de estos pares y elimina el programa si se detiene:
fuente
Brainfuck en Python, 567 bytes
Una solución relativamente simple, ya que Brainfuck no es el idioma más difícil para el que escribir un intérprete.
Esta implementación de Brainfuck tiene el puntero de datos que comienza en 0, solo se le permite tomar un valor positivo (se considera un error si intenta ir a la izquierda de 0). Las celdas de datos pueden tomar valores de 0 a 255 y ajustarse. Las 5 instrucciones válidas son
><+[]
(-
es innecesario debido al ajuste).Creo que la salida es correcta ahora, sin embargo, es difícil estar seguro de que está imprimiendo todas las soluciones posibles, por lo que es posible que me falte alguna.
Las primeras salidas:
Y una lista de los primeros 2000: http://pastebin.com/KQG8PVJn
Y, por último, una lista de los primeros resultados de 2000 con
[]
ellos: http://pastebin.com/iHWwJprs(todos los demás son triviales siempre que sean válidos)
Tenga en cuenta que la salida no está en un orden ordenado, aunque puede parecer así para muchos de ellos, ya que los programas que tardan más se imprimirán más adelante.
fuente
[-]
como el[+]
definitivamente deberían aparecer porque los contenidos del bucle simplemente se omiten (no involucra envoltura).[-]
y[+]
era un error que ahora debería solucionarse y he actualizado con la configuración.
? No es necesario para un subconjunto de BF completo de Turing y la salida debe ignorarse de todos modos. Además, dado que está ajustando los valores de las celdas, creo que solo necesita uno de-
y+
.barras en Python,
640498 byteshttps://esolangs.org/wiki////
Un programa de barras es una cadena, en este intérprete limitado a los caracteres '/' y '\'. En esta implementación, / es '1' y \ es '0' para permitir jugar al golf con el uso de bin (x) de python. Cuando el intérprete encuentra un \, se emite el siguiente carácter y se eliminan ambos caracteres. Cuando encuentra un /, busca patrones de búsqueda y reemplazo como / search / replace / incluyendo caracteres escapados dentro de los patrones (\\ representa \ y \ / representa /). Esa operación de reemplazo se realiza en la cadena repetidamente hasta que la cadena de búsqueda ya no esté presente, luego la interpretación continúa desde el principio nuevamente. El programa se detiene cuando está vacío. Se eliminará un programa si hay un conjunto no cerrado de / patrones o un \ sin ningún carácter después de él.
fuente
Treehugger en Java,
1,2991,2571,2511,2071,2031,2011,1931,189 bytesfuente
Brachylog → Problema de correspondencia posterior , 10 bytes
Pruébalo en línea!
Función que es un generador que genera todos los posibles problemas de correspondencia posterior para los cuales las soluciones de fuerza bruta finalmente se detienen. (Se sabe que las soluciones de fuerza bruta al problema de correspondencia posterior son una operación completa de Turing.) El enlace TIO contiene un encabezado que convierte un generador en un programa completo e imprime cada salida inmediatamente a medida que se genera (por lo tanto, cuando TIO mata el programa debido a que consume más de 60 segundos de tiempo de ejecución, la salida producida hasta ahora es visible).
Esto utiliza una formulación del problema en el que las cadenas se dan como cadenas de dígitos, no se permiten ceros a la izquierda excepto por
0
sí mismo, no se aceptan soluciones al problema que involucra ceros a la izquierda, y una cadena de dígitos puede representarse como el número , o menos el número. Claramente, nada de esto tiene ningún impacto en la integridad del lenguaje de Turing (porque no hay necesidad de un problema de correspondencia posterior para usar el dígito cero).Este programa funciona mediante la generación de todas las soluciones posibles a los problemas, y luego funciona hacia atrás para encontrar los programas originales que resuelven. Como tal, un programa individual puede salir muchas veces. No está claro si esto invalida la respuesta o no; tenga en cuenta que todos los programas de detención eventualmente saldrán al menos una vez (de hecho, infinitamente muchas veces, ya que cualquier programa que tenga soluciones tiene infinitas soluciones), y los programas que no se detengan nunca saldrán.
Explicación
fuente
"Púrpura sin E / S" en Ceilán, 662
El púrpura es un lenguaje de una sola instrucción que se modifica a sí mismo y se le pidió que lo interpretara aquí . Como entrada y salida no son relevantes para esta tarea, me quita el
o
significado del símbolo del intérprete, de tal manera que los símbolos (potencialmente) son sólo válidosa
,b
,A
,B
,i
y1
(la última sólo para leer, no por escrito).Pero como Purple se modifica a sí mismo (y usa su código fuente como datos), potencialmente también son útiles los programas que contienen otros caracteres, por lo que opté por permitir todos los caracteres ASCII imprimibles (sin espacios en blanco) en el código (otros podrían ser útil también, pero no se imprimen tan fácilmente).
(Puede modificar el intérprete para que, en su lugar, tome como una cadena de caracteres permitidos como argumento de la línea de comandos; cambie la línea comentada que se define a
a
continuación. Luego, la longitud se convierte en 686 bytes).Mi intérprete "paralelo" crea así todas las cadenas finitas de esos caracteres (en longitud creciente y orden lexicográfico) y prueba cada uno de ellos.
Purple se detendrá sin error cuando el comando que se leerá desde la cinta para su ejecución no sea válido, por lo tanto, no hay programas inválidos y muchos, muchos detenidos. (La mayoría se detiene incluso en el primer paso, solo algunos de los programas con duración 3 llegan al segundo paso (y se detendrán en ese momento), los primeros que no se detienen tienen longitud 6.
Creo que el primer programa que no se detiene en el orden probado por mi intérprete es
aaaiaa
, que en el primer paso establece ela
registro en 0 (que ya era), y el segundo y cada paso siguiente establece el puntero de instrucción nuevamente en 0, haciendo que se ejecuteiaa
nuevamente.Reutilicé parte del código escrito para mi intérprete de Purple "estándar" , pero debido a la eliminación de entrada y salida, mi intérprete paralelo se vuelve aún más corto que eso, al tiempo que incluye la lógica adicional para ejecutar múltiples programas a la vez.
Aquí hay una versión comentada y formateada:
fuente
Cálculo combinador SK en Haskell , 249 bytes
Pruébalo en línea!
Cómo funciona
Las reglas de evaluación de llamada por valor para el cálculo del combinador SK son las siguientes:
(a) S xyz ↦ xz ( yz ), para x , y , z en forma normal;
(b) K xy ↦ x , para x , y en forma normal;
(c) xy ↦ x ′ y , si x ↦ x ′;
(d) xy ↦ xy ′, para x en forma normal, si y ↦ y ′ .
Como solo estamos interesados en detener el comportamiento, ampliamos el lenguaje ligeramente al introducir un símbolo H que no está en forma normal, pero al que todas las formas normales "evalúan":
(a) S xyz ↦ xz ( yz ), para x , y , z en forma normal;
(b ') K x H ↦ x , para x en forma normal;
(c) xy ↦ x ′ y , si x ↦ x ′;
(d) xy ↦ xy ′, para x en forma normal, si y ↦ y ′ ;
(e) S ↦ H;
(f) K = H;
(g) SH ↦ H;
(h) KH ↦ H;
(i) SHH ↦ H.
Consideramos que cualquier aplicación H x es un error de tiempo de ejecución que debe tratarse como si fuera un bucle infinito, y ordenamos evaluaciones de modo que no se produzca H por (e) - (i) excepto en un contexto donde será ignorado (nivel superior, cualquier K x ☐, cualquier ignorado K☐, cualquier ignorado S x ☐ para x en forma normal, cualquier ignorado S☐H). De esta manera no afectamos el comportamiento de detención de los términos habituales que carecen de H.
Los beneficios de estas reglas modificadas son que cada término normalizable tiene una ruta de evaluación única a H, y que cada término tiene un número finito de posibles imágenes previas en ↦. Entonces, en lugar de utilizar el enfoque de cola de milano, podemos hacer una búsqueda mucho más eficiente de todas las rutas de evaluación inversa desde H.
n
comprueba si un término está en forma normal,f
encuentra todas las preimágenes posibles de un término yl
es una lista infinita perezosa de términos normalizables producidos por la búsqueda de amplitud de H.fuente