Eu sei que, em linguagens de programação imperativas, um loop while-do é suficiente como uma construção de fluxo de controle para tornar a linguagem Turing completa (no que diz respeito ao fluxo de controle - é claro que também precisamos de memória ilimitada e de certos operadores ...) . A essência da minha pergunta é: um loop do-while tem o mesmo poder computacional que um loop do while? Em outras palavras, um idioma pode ser completo em Turing se for impossível ignorar completamente as instruções.
Sei que algumas das semânticas aqui podem ser um pouco ambíguas, então deixe-me formular a pergunta real com um exemplo específico:
Brainfuck (BF) é um tarpit de Turing em que o único fluxo de controle é um loop while-do, indicado como [...]
(há uma especificação completa de idioma na parte inferior da pergunta, caso você não esteja familiarizado com Brainfuck). Vamos definir uma nova linguagem BF *, em que ,.+-<>
tenha a mesma semântica que em BF, mas em vez de a []
que temos, {}
denota um loop do-while. Ou seja, a única diferença para o BF é que cada loop é executado pelo menos uma vez antes que outras iterações possam ser puladas.
O BF * Turing está completo? Se for, eu estaria interessado em como eu poderia traduzir BF para BF *. Se não for, como faço para provar isso?
Algumas observações minhas:
- Nem todo programa BF pode ser traduzido para BF *. Por exemplo, é impossível escrever um programa em BF * que possa ou não ler ou imprimir um valor - se o programa potencialmente imprimir um ou mais valores, sempre imprimirá pelo menos um. No entanto, pode haver um subconjunto completo de Turing do BF que pode ser traduzido para o BF *.
- Não podemos simplesmente traduzir
[f]
(ondef
existe algum programa Brainfuck arbitrário constituído apenas por+-[]<>
) para (em uma tentativa de cancelar o efeito da primeira iteração), porque a) nem toda função computável tem um inverso computável eb) mesmo que tivesse, não necessariamente terá menos loops do que a aplicação recursiva dessa etapa não é garantida para terminar em primeiro lugar.f-1{f}
f-1
f
Aqui está uma rápida visão geral sobre o idioma Brainfuck. Brainfuck opera em uma fita infinita onde cada célula contém valores de bytes, inicialmente zero. Os estouros são contornados, então o aumento de 255 fornece 0 e vice-versa. O idioma consiste em 8 instruções:
+ 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 [.
[]
não está definindo exatamente um loop "while do" no BF. como em sua tabela, os colchetes esquerdo e direito avaliam a célula atual zero / diferente de zero. então, qual é a descrição exata da{}
lógica de avaliação de chaves correspondente ? sugerir mais diálogo / discussão no bate-papo sobre ciência da computação . também suas "observações" são mais parecidas com "postulados" ou "proposições" sem provas.{}
seria{
fazer nada e}
igual a]
. Não terei muito tempo nos próximos dias, mas me juntarei a você no bate-papo quando encontrar algum tempo.{}
e retirada[]
, é AM * Turing completo. com o entendimento de que o BF[]
é uma construção apenas algo parecido / análogo a um loop while-do em linguagens completas de Turing.Respostas:
Eu não conheço Brainfuck, então você terá que fazer alguma tradução do meu pseudocódigo. Mas, supondo que Brainfuck se comporte de maneira sensata (ha!), Tudo a seguir deve ser aplicado.
do-while é equivalente a while-do.
do X while Y
é equivalente aX; while Y do X
e, supondo que você tenha condicionais,while Y do X
é equivalente aif Y then (do X while Y)
.A vida é um pouco mais difícil se você não tem condicionais. Se você tem um tempo de atividade, pode simular
if Y then X
usando algo como isto:Mas e se você tiver apenas um tempo? Eu afirmo que o seguinte simula
if Y then X
, assumindo queX
termina dado o valor atual das variáveis. (Isso não é garantido: o programaif y=0 then loopforever
termina sey != 0
, embora faça umX
loop para qualquer valor das variáveis). SejaV1
, ...,Vn
as variáveis modificadas porX
e deixeX'
serX
modificadas para serem usadas emVi'
vez deVi
para cada uma dessas variáveis.swap(A,B)
denota o código óbvio que troca as variáveisA
eB
.A ideia é a seguinte. Primeiro, suponha que isso
Y
seja falso. Simulamos fazerX
uma vez e armazenamos os resultados emV1''
, ...,Vn''
;V1'
, ...,Vn'
mantenha os valores originais deV1
, ...,Vn
. Então, atribuímosV1 := V1'; ...; Vn := Vn'
, o que não faz nada. Então, seY
for falso, não fizemos nada. Agora, suponha que issoY
seja verdade. Agora simularemosX
duas vezes , armazenando os resultados nas variáveis "iniciadas" e "iniciadas duas vezes". Portanto, agora, as atribuições no final do loop têm o efeitoX
calculado uma vez. Observe queY
depende apenas das variáveis "não criadas", portanto, seu valor não é afetado pela execução repetida do loop.OK, e daí se
X
não for possível finalizar o valor atual das variáveis? (Agradecemos a Martin Ender por apontar essa possibilidade.) Nesse caso, precisamos simularX
instrução por instrução, usando idéias semelhantes às descritas acima. Cada instrução definitivamente termina para que possamos usar a primeira instrução da.if
simulação acima para decodificar as instruções, seguindo as linhas de "Se o código de operação for foo, faça isso; se for barra, faça isso; ...". Então, agora, usamos um loop para iterar pelas instruções deX
, usando um ponteiro de instruções e assim por diante, para sabermos qual instrução executar a seguir. No final de cada iteração do loop, verifiqueY
e verifique seX
ainda parou. SeY
for falso, a técnica de troca nos permite desfazer os efeitos deX
fonte
Y
é falso, masX
não termina no conjunto atual de valores de variáveis.if Y then X
termina, mas sua tradução não, porque sempre precisa ser executadaX'
pelo menos uma vez.X
instrução por instrução e verificarY
após cada instrução. Cada instrução é garantida para terminar, para que tudo funcione. Mas é uma pena escrever.X
assim se começar com um loop while / próprio. Vou ter que pensar um pouco mais sobre isso.X'
não for linear. Você se importaria em incluir mais alguns detalhes de um brinquedo simples, mas não trivialX
? Por exemplodo (while A do B) while C
? (o exteriordo while
vem do exteriorwhile do
que estamos traduzindo atualmente)