Je sais que, dans les langages de programmation impératifs, une boucle while-do est suffisante comme construction de flux de contrôle pour rendre le langage Turing complet (en ce qui concerne le flux de contrôle - bien sûr, nous avons également besoin d'une mémoire illimitée et de certains opérateurs ...) . L'essentiel de ma question est: une boucle do-while a-t-elle la même puissance de calcul qu'une boucle while-do? En d'autres termes, une langue peut-elle être complète de Turing s'il est impossible de sauter complètement les instructions.
Je me rends compte que certaines sémantiques ici pourraient être un peu ambiguë, alors laissez-moi formuler la question réelle avec un exemple spécifique:
Brainfuck (BF) est un tarpit Turing où le seul flux de contrôle est une boucle while-do, notée [...]
(il y a une spécification de langue complète au bas de la question, au cas où vous n'êtes pas familier avec Brainfuck). Définissons un nouveau langage BF *, où ,.+-<>
ont la même sémantique que dans BF, mais au lieu de []
nous avons {}
qui dénote une boucle do-while. Autrement dit, la seule différence avec BF est que chaque boucle est exécutée au moins une fois avant que d'autres itérations puissent être ignorées.
BF * Turing est-il complet? Si c'est le cas, je serais intéressé par la façon dont je pourrais traduire BF en BF *. Si ce n'est pas le cas, comment puis-je le prouver?
Quelques observations personnelles:
- Tous les programmes BF ne peuvent pas être traduits en BF *. Par exemple, il est impossible d'écrire un programme en BF * qui peut ou non lire ou imprimer une valeur - si le programme imprime potentiellement une ou plusieurs valeurs, il en imprimera toujours au moins une. Cependant, il pourrait y avoir un sous-ensemble complet de Turing de BF qui peut être traduit en BF *.
- Nous ne pouvons pas simplement traduire
[f]
(oùf
est un programme Brainfuck arbitraire composé uniquement de+-[]<>
) en (pour tenter d'annuler l'effet de la première itération), car a) toutes les fonctions calculables n'ont pas un inverse calculable et b) même si c'était le cas, n'aurait pas nécessairement moins de boucles que si l'application de cette étape de manière récursive n'est pas garantie de se terminer en premier lieu.f-1{f}
f-1
f
Voici un bref aperçu de la langue de Brainfuck. Brainfuck fonctionne sur une bande infinie où chaque cellule contient une valeur d'octets, initialement zéro. Les débordements s'enroulent, donc l'incrémentation de 255 donne 0 et vice versa. La langue se compose de 8 instructions:
+ 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 [.
[]
ne définit pas exactement une boucle "while do" dans BF. comme dans votre tableau, les crochets gauche et droit évaluent la cellule actuelle zéro / non nulle. alors quelle est la description exacte de la{}
logique d'évaluation des accolades correspondante ? suggérer d'autres dialogues / discussions dans le chat informatique . aussi vos "observations" sont plutôt des "postulats" ou des "propositions" sans preuve.{}
serait de{
ne rien faire du tout et de}
la même manière que]
. Je n'aurai pas beaucoup de temps au cours des prochains jours, mais je vous rejoindrai dans le chat lorsque j'en trouverai un peu.{}
et un prélèvement donnés[]
, le BF * Turing est complet. avec la compréhension que BF[]
est une construction seulement quelque chose de quelque chose comme / analogue à une boucle while-do dans les langages complets de Turing.Réponses:
Je ne connais pas Brainfuck, vous devrez donc faire une traduction de mon pseudocode. Mais, en supposant que Brainfuck se comporte raisonnablement (ha!), Tout ce qui suit devrait s'appliquer.
do-while est équivalent à while-do.
do X while Y
est équivalent àX; while Y do X
et, en supposant que vous avez des conditions,while Y do X
est équivalent àif Y then (do X while Y)
.La vie est un peu plus difficile si vous n'avez pas de conditionnels. Si vous avez du temps, vous pouvez simuler en
if Y then X
utilisant quelque chose comme ceci:Mais que faire si vous n'avez que du temps? Je prétends que ce qui suit simule
if Y then X
, en supposant que seX
termine étant donné la valeur actuelle des variables. (Ce n'est pas garanti: le programme seif y=0 then loopforever
termine siy != 0
, même s'ilX
boucle pour n'importe quelle valeur des variables). SoitV1
, ...,Vn
les variables modifiées parX
et laissonsX'
êtreX
modifié de sorte qu'il utilise à laVi'
place deVi
chacune de ces variablesswap(A,B)
désigne le code évident qui permute les variablesA
etB
.L'idée est la suivante. Tout d'abord, supposons que
Y
c'est faux. Nous simulons faireX
une fois et stockons les résultats dansV1''
, ...,Vn''
;V1'
, ...,Vn'
maintiennent les valeurs d'origine deV1
, ...,Vn
. Ensuite, nous attribuonsV1 := V1'; ...; Vn := Vn'
, ce qui ne fait rien. Donc, siY
c'est faux, nous n'avons rien fait. Maintenant, supposons queY
c'est vrai. Nous allons maintenant simulerX
deux fois , en stockant les résultats dans les variables "primed" et "double-primed". Donc, maintenant, les affectations à la fin de la boucle ont l'effet qui aX
été calculé une fois. Notez que celaY
ne dépend que des variables "non amorcées", donc sa valeur n'est pas affectée par l'exécution répétée de la boucle.OK, que se passe-t-il si
X
cela ne se termine pas pour la valeur actuelle des variables? (Merci à Martin Ender d'avoir souligné cette possibilité.) Dans ce cas, nous devons simulerX
instruction par instruction, en utilisant des idées similaires à celles ci-dessus. Chaque instruction se termine définitivement afin que nous puissions utiliser laif
simulation ci-dessus pour effectuer le décodage des instructions, sur le modèle "Si l'opcode est fou, faites ceci; si c'est une barre, faites cela; ...". Donc, maintenant, nous utilisons une boucle pour parcourir les instructions deX
, en utilisant un pointeur d'instruction et ainsi de suite afin de savoir quelle instruction exécuter ensuite. À la fin de chaque itération de la boucle, vérifiezY
et vérifiez siX
elle s'est encore arrêtée. SiY
est faux, la technique de permutation nous permet d'annuler les effets deX
est la première instruction.la source
Y
est faux maisX
ne se termine pas sur l'ensemble actuel de valeurs de variable.if Y then X
se termine, mais pas votre traduction, car elle doit toujours être exécutéeX'
au moins une fois.X
instruction par instruction et vérifierY
après chaque instruction. La fin de chaque instruction est garantie afin que tout fonctionne. Mais c'est pénible à écrire.X
comme ça s'il commence par une boucle while / conditionnelle elle-même. Je vais devoir y penser un peu plus.X'
est non linéaire. Pourriez-vous inclure plus de détails pour un jouet simple mais non trivialX
? Par exempledo (while A do B) while C
? (l'extérieurdo while
vient de l'extérieurwhile do
que nous traduisons actuellement)