Sé que, en los lenguajes de programación imperativos, un bucle while-do es suficiente como una construcción de flujo de control para completar el lenguaje Turing (en lo que respecta al flujo de control, por supuesto, también necesitamos memoria ilimitada y ciertos operadores ...) . La esencia de mi pregunta es: ¿un ciclo do-while tiene el mismo poder computacional que un ciclo while-do? En otras palabras, ¿puede un idioma ser Turing completo si es imposible omitir las instrucciones por completo?
Me doy cuenta de que algunas de las semánticas aquí podrían ser un poco ambiguas, así que permítanme formular la pregunta real con un ejemplo específico:
Brainfuck (BF) es un tarpit de Turing donde el único flujo de control es un ciclo while-do, denotado como [...](hay una especificación de lenguaje completa en la parte inferior de la pregunta, en caso de que no esté familiarizado con Brainfuck). Definamos un nuevo lenguaje BF *, donde ,.+-<>tenga la misma semántica que en BF, pero en lugar de la []que tenemos, {}denota un ciclo do-while. Es decir, la única diferencia con BF es que cada bucle se ejecuta al menos una vez antes de que se puedan omitir más iteraciones.
¿Está BF * Turing completo? Si es así, me interesaría cómo podría traducir BF a BF *. Si no es así, ¿cómo pruebo eso?
Algunas observaciones mías:
- No todos los programas BF se pueden traducir a BF *. Por ejemplo, es imposible escribir un programa en BF * que pueda o no leer o imprimir un valor; si el programa potencialmente imprime uno o más valores, siempre imprimirá al menos uno. Sin embargo, puede haber un subconjunto de BF completo de Turing que se puede traducir a BF *.
- No podemos simplemente traducir
[f](dondefhay algún programa arbitrario, Brainfuck que consiste solo en+-[]<>) a (en un intento de cancelar el efecto de la primera iteración), porque a) no todas las funciones computables tienen un inverso computable yb) incluso si lo hiciera, no necesariamente tendría menos bucles que, por lo tanto, aplicar este paso de forma recursiva no garantiza que termine en primer lugar.f-1{f}f-1f
Aquí hay una descripción rápida sobre el lenguaje Brainfuck. Brainfuck opera en una cinta infinita donde cada celda contiene valores de bytes, inicialmente cero. Los desbordamientos se envuelven, por lo que al incrementar 255 se obtiene 0 y viceversa. El lenguaje consta de 8 instrucciones:
+ Increment the current cell.
- Decrement the current cell.
> Move tape head to the right.
< Move tape head to the left.
, Input a character from STDIN into the current cell.
. Output the current cell as a character to STDOUT.
[ If the current cell is zero, jump past the matching ].
] If the current cell is non-zero, jump back to just behind the matching [.

[]no está definiendo exactamente un bucle "while do" en BF. Como en su tabla, los corchetes izquierdo y derecho evalúan la celda actual cero / no cero. Entonces, ¿cuál es la descripción exacta de la{}lógica de evaluación de llaves correspondiente ? Sugerir más diálogo / discusión en Computer Science Chat . también sus "observaciones" son más como "postulados" o "proposiciones" sin prueba.{}sería{no hacer nada en absoluto y}lo mismo]. No tendré mucho tiempo en los próximos días, pero me reuniré con usted en el chat cuando encuentre algo de tiempo.{}y quitando[], es BF * Turing completo. con el entendimiento de que BF[]es una construcción solo algo similar / análogo a un ciclo while-do en los lenguajes completos de Turing.Respuestas:
No sé Brainfuck, así que tendrás que hacer alguna traducción de mi pseudocódigo. Pero, suponiendo que Brainfuck se comporte con sensatez (¡ja!), Todo lo que sigue debe aplicarse.
do-while es equivalente a while-do.
do X while Yes equivalente aX; while Y do Xy, suponiendo que tenga condicionales,while Y do Xes equivalente aif Y then (do X while Y).La vida es un poco más difícil si no tienes condicionales. Si tiene while-do, puede simular
if Y then Xusando algo como esto:Pero, ¿qué pasa si solo tienes do-while? Afirmo que lo siguiente simula
if Y then X, suponiendo queXtermina dado el valor actual de las variables. (Esto no está garantizado: el programaif y=0 then loopforevertermina siy != 0, a pesar de que realiza unXbucle para cualquier valor de las variables). SeanV1, ...,Vnlas variables modificadas porXyX'seanXmodificadas para que se utilicen enVi'lugar deVipara cada una de esas variables.swap(A,B)denota el código obvio que intercambia las variablesAyB.La idea es la siguiente. Primero, suponga que eso
Yes falso. Simulamos hacerXuna vez, y almacenamos los resultados enV1'', ...,Vn'';V1', ...,Vn'mantenga los valores originales deV1, ...,Vn. Luego, asignamosV1 := V1'; ...; Vn := Vn', que no hace nada. Entonces, siYes falso, no hemos hecho nada. Ahora, supongamos que esoYes cierto. Ahora simularemosXdos veces , almacenando los resultados en las variables "cebado" y "cebado doble". Entonces, ahora, las asignaciones al final del ciclo tienen el efecto queXse calculó una vez. Tenga en cuenta queYsolo depende de las variables "sin imprimir", por lo que su valor no se ve afectado al ejecutar el bucle repetidamente.Bien, ¿y qué tal si
Xno termina el valor actual de las variables? (Gracias a Martin Ender por señalar esta posibilidad). En ese caso, necesitamos simularXinstrucción por instrucción, usando ideas similares a las anteriores. Cada instrucción definitivamente termina para que podamos usar laifsimulación anterior para hacer la decodificación de instrucciones, en la línea de "Si el código de operación es foo, haz esto; si es bar, haz eso; ...". Entonces, ahora, usamos un bucle para iterar a través de las instrucciones deX, usando un puntero de instrucción y así sucesivamente para que sepamos qué instrucción ejecutar a continuación. Al final de cada iteración del ciclo, verifiqueYy verifique si seXha detenido todavía. SiYes falso, la técnica de intercambio nos permite deshacer los efectos deXLa primera instrucción.fuente
Yes falso peroXno termina en el conjunto actual de valores variables.if Y then Xtermina, pero su traducción no, porque siempre debe ejecutarseX'al menos una vez.Xinstrucción por instrucción y verificarYdespués de cada instrucción. Se garantiza que cada instrucción terminará para que todo funcione. Pero es un dolor escribirlo.Xasí si comienza con un ciclo while / condicional. Tendré que pensar en esto un poco más.X'no es lineal. ¿Te importaría incluir más detalles para un juguete simple pero no trivialX? Por ejemplodo (while A do B) while C? (lo externodo whileviene de lo externowhile doque estamos traduciendo actualmente)