Aviso: estou disposto a dar uma recompensa a qualquer resposta que eu ache interessante.
Seu desafio é projetar um computador com um conjunto de instruções (OISC) completo :
Um OISC é uma máquina abstrata que usa apenas uma instrução - evitando a necessidade de um código de operação de linguagem de máquina. Com uma escolha criteriosa para a instrução única e com recursos infinitos, um OISC é capaz de ser um computador universal da mesma maneira que os computadores tradicionais que possuem várias instruções.
Aqui estão alguns exemplos de comandos únicos que formam um OISC completo para Turing.
Regras:
Você deve fornecer uma interpretação ou prova disso
Você deve fornecer um intérprete para o seu idioma. Esse intérprete deve ser restrito apenas pela memória / hora (por exemplo, não deve haver restrições impostas pelo usuário). Se você não fornecer um intérprete para o seu idioma (por qualquer motivo que não seja a preguiça), você deve provar que é possível que um seja escrito. Um intérprete deve ser possível .
Você deve provar sua integridade de Turing
Você deve incluir uma prova formal de que seu idioma está completo em Turing. Uma maneira simples de fazer isso é provar que ele pode interpretar ou ter o mesmo comportamento de outra linguagem completa de Turing. A linguagem mais básica para interpretar seria Brainf ** k .
Por exemplo, um idioma normal que possui todos os mesmos comandos que o Brainf ** k (e a mesma falta de restrições de memória impostas pelo usuário) está completo com Turing porque qualquer coisa que possa ser implementada no Brainf ** k pode ser implementada no idioma .
Aqui está uma lista de linguagens completas de Turing muito simples de implementar.
Requisitos adicionais do OISC
Esse OISC deve ter apenas uma instrução - não pode ter várias instruções, sendo que uma delas o torna completo em Turing.
Seu OISC pode usar qualquer sintaxe que você desejar. Você deve definir em sua resposta o que é instrução, o que são dados e o que é um não operacional (por exemplo, espaço em branco). Seja criativo!
Os argumentos não precisam ser apenas números inteiros. Por exemplo, /// é um belo exemplo de um OISC completo de Turing.
Como e se as entradas e saídas são obtidas e fornecidas são deixadas por você. A maioria dos OISCs implementa E / S através de locais específicos de memória, mas pode haver outras maneiras de fazê-lo, e você é incentivado a encontrar uma.
Uma resposta válida deve fornecer um código de exemplo no seu OISC, incluindo-o na postagem ou vinculando-o a um simples desafio resolvido no idioma.
Votação
Eleitores, lembre-se de não aprovar envios chatos. Exemplos:
- Linguagem- equivalentes
- Uma implementação de um OISC existente (respondedores, crie o seu próprio!)
- Um "OISC" no qual o primeiro argumento especifica um comando para chamar ( exemplo )
No entanto, você deve votar em envios de criativos interessantes, como:
- Um OISC baseado em uma equação matemática
- Um ZISC completo de Turing baseado em uma rede neural
- Um OISC no qual a E / S de saída ocorre de outras maneiras que não certos locais de memória
Ganhando
Como no concurso de popularidade , a resposta com mais votos ganha! Boa sorte!
Respostas:
XOISC
Este OISC é baseado no combinador X da Fokker, que é definido da seguinte forma:
Se reconhecermos o fato de que o cálculo do SKI é Turing completo, o -bin acima também é Turing completo. Isso ocorre porque S , K e eu podemos ser escritos em termos de X , assim:X S K I X
Como o XOISC funciona
Internamente, o XOISC tem uma pilha (inicialmente vazia); a partir daí, a instrução que toma como argumento faz o seguinte:n
Quando não houver mais instruções, o XOISC enviará todos os argumentos da linha de comando (se houver) para a pilha, por exemplo:
O cálculo final será .(…((…(s1 s2)…) sM) a1)…)aN
Como a única instrução no XOISC usa apenas um argumento (deslocamento de memória), não há razão para usar um nome para essa instrução. Portanto, um arquivo de origem válido constituirá apenas números inteiros separados por novas linhas ou espaços em branco, como por exemplo:
Experimente online!
Exemplo
Vamos pegar o exemplo acima (pilha crescendo para a direita):
Por fim, avalie a pilha: ou com menos parênteses X ( X X ) ( X X ) ( X X ) que reconhecemos como a boa e velha identidade S K K função.((X (X X)) (X X)) (X X) X (X X) (X X) (X X) S K K
Conclusão de Turing
Ideia de prova
Para que o XOISC seja Turing completo, precisamos ser capazes de traduzir qualquer intercalação (válida) de parênteses e combinadores Isso é possível porque, quando popping, aplicando e pressionando, o faz de maneira associativa à direita (o aplicativo de função é associativo à esquerda).X
Para converter qualquer expressão existe uma maneira fácil de fazê-lo: Sempre apareça tantos elementos que, desde o início do nível atual de parênteses, restará apenas um elemento.X
Como exemplo, a expressão usada anteriormente:((X (X X)) (X X)) (X X)
0
0
2
0
2
Então, acabamos com um programa XOISC diferente (mas semântica equivalente):
0 0 2 0 2 0 2
Experimente online!Se permanecermos nessa estratégia, podemos facilmente transformar qualquer expressão que consiste em combinadores em um programa XOISC que deixa apenas uma única função na pilha.X
Prova formal
Dado que o cálculo do SKI é Turing completo, precisamos mostrar duas coisas:
A primeira parte - provar as três igualdades na introdução - é muito entediante e consome espaço, também não é muito interessante. Então, em vez de colocá-lo neste post, você pode encontrar aqui * .
0
Intérprete
Entradas
Como o cálculo lambda não digitado exige que definamos nossos próprios tipos de dados para tudo o que queremos e isso é complicado, o intérprete está ciente dos números da Igreja - isso significa que, quando você fornece entradas, ele automaticamente transforma os números no número correspondente da Igreja.
Como exemplo, aqui está um programa que multiplica dois números: Experimente online!
Você também pode fornecer funções como argumentos usando índices De Bruijn , por exemplo, o
S
combinador\\\(3 1 (2 1))
(ouλλλ(3 1 (2 1))
). No entanto, também reconhece aS
,K
,I
e, claro,X
combinator.Saída
Por padrão, o intérprete verifica se a saída codifica um número inteiro; caso isso aconteça, ele gera o número correspondente (além do resultado). Por conveniência, há o
-b
sinalizador que diz ao intérprete para tentar combinar um booleano (veja o último exemplo).Montador
É claro que qualquer linguagem de baixo nível precisa de um assembler que converta uma linguagem de alto nível para ela; você pode simplesmente usar qualquer entrada (veja acima) e traduzi-la para um programa XOISC usando a
-a
bandeira, tente on-line! *** Caso o link esteja inoperante, há uma cópia como comentário em HTML nesta postagem.
** Isso resulta em um programa que testa primalidade, experimente online!
fonte
Desenhar
Draw é um OISC atuando em uma grade 2D, marcando quadrados de maneira semelhante à máquina B de Wang. No entanto, para manter o idioma o mais simples e OISC-y possível, todas as instruções (das quais há um total de um) marcam o quadrado que acabou de pisar e, para poder parar, pisando em um quadrado marcado finaliza o programa.
O programa consiste em uma sequência de linhas contendo um identificador de linha (sequência arbitrária que não inclui # ou espaço em branco), dois números inteiros (
x
ey
) e mais dois identificadores de linha (a
eb
).O programa é executado como se segue:
Começando na linha identificada como
start
com o ponteiro que aponta para a posição (0, 0), mover o indicador, o valor dado porx
ey
e marcar o quadrado do ponteiro está agora em (a menos que o quadrado já está marcado, nesse caso, a execução termina). Em seguida, pule para a linhaa
se pelo menos um dos quadrados diretamente adjacentes também estiver marcado e,b
caso contrário , para a linha .Os intérpretes são incentivados a exibir o resultado final da grade como algum tipo de imagem, tela, etc.
Completude de Turing
Draw é Turing-complete, pois é possível compilar uma versão modificada (chamada Alternate) de uma máquina Minsky no idioma.
O alternativo age de maneira semelhante a uma máquina Minsky de dois contadores, mas há uma grande restrição nos comandos: os comandos devem alternar entre direcionar o primeiro e o segundo contadores. Para contornar esta modificação, foi adicionado um comando adicional:
nop
. Este comando não altera o contador de destino, o que possibilita "alterar" alterações consecutivas em um contador, satisfazendo a restrição descrita acima. Isso também significa que o registro a ser modificado não precisa ser fornecido e, para qualquer instrução, pode ser deduzido diretamente das instruções das quais a execução pode pular para ele.Exemplo: esta máquina Minsky
se transforma neste programa alternativo:
Essa restrição é necessária devido à maneira como o eventual programa Draw lida com os registros, ou seja, não faz nenhuma diferença entre eles. Em vez disso, o programa Draw simplesmente copia o registro que não foi alterado pela instrução anterior, modificando-o de acordo com a instrução que está sendo executada.
Em seguida, o programa alternativo é convertido diretamente no Draw da seguinte maneira:
O programa começa com este bloco.
inc
,dec
Enop
são convertidos em quase da mesma forma como cada outra. Em todos os casos, não há diferença entre alterar o primeiro ou o segundo registrador (como explicado acima). Aqui está um incremento, equivalente ainc 2
:Altere os números nas
i1_x
partes para o índice da instrução atual e nasi2_x
partes para o índice da próxima instrução a ser executada.A
nop
instrução pode ser traduzida como tal:Este é um decréscimo:
i3_x
refere-se à instrução a ser chamada se o contador já for 1.Parar:
Troque os rótulos de maneira apropriada e simplesmente encadeie tudo. Fazer isso no exemplo acima fornece o programa Draw no repositório acima.
Intérpretes
Atualmente, existem dois intérpretes, ambos escritos em Python. Eles podem ser encontrados no repositório GitHub do Draw .
objetivo errado, levando a fonte através de uma caixa pop-up ao iniciar o script. O Golly pode ser um pouco exigente com o Python, portanto, certifique-se de ter o Python 2 instalado (e não misture o Golly de 32 bits com o Python de 64 bits ou vice-versa). A saída é fornecida pela grade de células incorporada da Golly.A imagem a seguir é um exemplo de saída do segundo intérprete. A execução do programa de exemplo no repositório fornece isto (ou similar):
fonte
-3
Aqui está a essência.
Memória
A memória é um mapa de fitas, onde as teclas são cadeias de caracteres e os valores são números inteiros de tamanho arbitrário.
Além disso, há um conjunto de rótulos nos quais o programa pode ir.
Há uma pilha que contém os operandos, que são cadeias de caracteres.
Há uma violação, que controla onde as fitas da memória podem ser acessadas.
A única instrução
-
. Primeiro, eleLABEL
tira uma string da pilha. Se isso nãoLABEL
estiver definido como rótulo, ele define o rótulo e limpa a fonte desse rótulo (ou seja, de onde foi enviado) e a instrução atual. Caso contrário, ele executa o seguinte cálculo, usando os dois principais valoresA
eB
:Observe que, se houver argumentos em excesso ou insuficientes, o programa apresentará erros, mostrando o estado do programa.
O deslocamento pode ser modificado acessando o valor de
.
.Código de exemplo
Isso define a variável
i
como7
, incrementando os7
tempos.Isso multiplica
i+1
pela constante2
.Prova de Completude de Turing
Desconsiderando os tamanhos int do C ++ (isto é, supondo que sejam infinitos), -3 é Turing Complete por redução para o cérebro de três células . Posso desconsiderar esse tamanho, pois pode ser gravado um intérprete para -3 em um computador com memória infinita que possui células arbitrariamente grandes.
Eu também acredito que qualquer BCT pode ser escrito como um programa -3.
fonte