Remarque: je suis prêt à donner une prime à toute réponse que je trouve intéressante.
Votre défi consiste à concevoir un ordinateur à un jeu d'instructions complet de Turing (OISC):
Un OISC est une machine abstraite qui utilise une seule instruction, ce qui évite d'avoir à utiliser un opcode en langage machine. Avec un choix judicieux pour l'instruction unique et des ressources infinies données, un OISC est capable d'être un ordinateur universel de la même manière que les ordinateurs traditionnels qui ont plusieurs instructions.
Voici quelques exemples de commandes uniques qui font un OISC complet de Turing.
Règles:
Vous devez fournir une interprétation ou une preuve de celle-ci
Vous devez fournir un interprète pour votre langue. Cet interpréteur ne doit être limité que par la mémoire / l'heure (par exemple, il ne doit pas avoir de restrictions imposées par l'utilisateur). Si vous ne fournissez pas d'interprète pour votre langue (pour une raison autre que la paresse), vous devez prouver qu'il est possible d'en rédiger un. Un interprète doit être possible .
Vous devez prouver son intégralité Turing
Vous devez inclure une preuve formelle que votre langue est Turing-complete. Un moyen simple de le faire est de prouver qu'il peut interpréter ou avoir le même comportement qu'un autre langage complet de Turing. La langue la plus élémentaire à interpréter serait Brainf ** k .
Par exemple, un langage normal qui a toutes les mêmes commandes que Brainf ** k (et le même manque de restrictions de mémoire imposées par l'utilisateur) est Turing-complete car tout ce qui peut être implémenté dans Brainf ** k peut être implémenté dans la langue .
Voici une liste de langages Turing-complete très simples à implémenter.
Exigences supplémentaires de l'OISC
Cet OISC ne doit avoir qu'une seule instruction - il ne peut pas avoir plusieurs instructions, l'une d'entre elles le rendant Turing-complet.
Votre OISC peut utiliser n'importe quelle syntaxe que vous aimez. Vous devez définir dans votre réponse ce qu'est une instruction, ce qui est des données et ce qu'est un no-op (par exemple un espace blanc). Sois créatif!
Les arguments ne doivent pas simplement être des entiers. Par exemple, /// est un bel exemple d'OISC complet de Turing.
La façon dont les entrées et les sorties sont prises et données vous appartient. La plupart des OISC implémentent les E / S via des emplacements de mémoire spécifiques, mais il peut y avoir d'autres moyens de le faire, et vous êtes encouragés à en trouver un.
Une réponse valide doit fournir un exemple de code dans votre OISC, soit en l'incluant dans le message, soit en établissant un lien vers un défi simple résolu dans la langue.
Vote
Votants, n'oubliez pas de ne pas voter de façon ennuyeuse. Exemples:
- Lenguage - équivalents
- Une implémentation d'un OISC existant (répondeurs, veuillez créer le vôtre!)
- Un "OISC" dans lequel le premier argument spécifie une commande à appeler ( exemple )
Cependant, vous devriez voter pour des soumissions créatives intéressantes, telles que:
- Un OISC basé sur une équation mathématique
- Un ZISC complet de Turing basé sur un réseau de neurones
- Un OISC dans lequel les E / S de sortie se produisent autrement que dans certains emplacements de mémoire
Gagnant
Comme pour le concours de popularité , la réponse avec le plus de votes gagne! Bonne chance!
Réponses:
XOISC
Cet OISC est basé sur le combinateur X de Fokker qui est défini comme suit:
Comment fonctionne XOISC
Une fois qu'il ne reste plus d'instructions, XOISC poussera tous les arguments de ligne de commande (le cas échéant) vers la pile, par exemple:
Étant donné que la seule instruction dans XOISC ne prend qu'un seul argument (décalage de mémoire), il n'y a aucune raison d'utiliser même un nom pour cette instruction. Un fichier source valide sera donc constitué uniquement d'entiers séparés par des sauts de ligne ou des espaces blancs, comme par exemple:
Essayez-le en ligne!
Exemple
Prenons l'exemple ci-dessus (la pile s'agrandit vers la droite):
Turing exhaustivité
Idée de preuve
0
0
2
0
2
Nous nous retrouvons donc avec un programme XOISC différent (mais sémantiquement équivalent):
0 0 2 0 2 0 2
Essayez-le en ligne!Preuve formelle
Étant donné que le SKI-calcul est Turing complet, nous devons montrer deux choses:
La première partie - prouver les trois égalités dans l'introduction - est très fastidieuse et encombrante, elle n'est pas non plus très intéressante. Donc, au lieu de le mettre dans cet article, vous pouvez le trouver ici * .
0
Interprète
Contributions
Étant donné que le calcul lambda non typé nous oblige à définir nos propres types de données pour tout ce que nous voulons et que cela est lourd, l'interprète connaît les chiffres de l' Église - cela signifie que lorsque vous fournissez des entrées, il transformera automatiquement les nombres en leur chiffre d'église correspondant.
À titre d'exemple, voici un programme qui multiplie deux nombres: Essayez-le en ligne!
Vous pouvez également fournir des fonctions comme arguments en utilisant les indices De Bruijn , par exemple le
S
combinateur\\\(3 1 (2 1))
(ouλλλ(3 1 (2 1))
). Toutefois , elle reconnaît aussi leS
,K
,I
et bien sûrX
Combinator.Sortie
Par défaut, l'interpréteur vérifie si la sortie code un entier, si c'est le cas, elle affichera le nombre correspondant (en plus du résultat). Pour plus de commodité, il y a le
-b
drapeau qui dit à l'interpréteur d'essayer de faire correspondre un booléen à la place (voir le dernier exemple).Assembleur
Bien sûr, tout langage de bas niveau a besoin d'un assembleur qui lui convertit un langage de haut niveau, vous pouvez simplement utiliser n'importe quelle entrée (voir ci-dessus) et le traduire en programme XOISC en utilisant le
-a
drapeau, essayez-le en ligne! *** Dans le cas où le lien est en baisse, il y a une copie en commentaire HTML dans cet article.
** Il en résulte un programme qui teste la primalité, essayez-le en ligne!
la source
Dessiner
Draw est un OISC agissant sur une grille 2D, marquant les carrés d'une manière similaire à la machine Wang B. Cependant, pour garder le langage aussi simple et OISC-y que possible, toutes les instructions (dont il y a un grand total d'un) marquent le carré qui vient d'être foulé et, pour pouvoir s'arrêter, marcher sur un carré marqué termine le programme.
Le programme se compose d'une séquence de lignes contenant un identifiant de ligne (chaîne arbitraire n'incluant pas # ni espace), deux entiers (
x
ety
) et deux autres identificateurs de ligne (a
etb
).Le programme s'exécute comme suit: en
commençant par la ligne identifiée comme
start
avec le pointeur pointant vers la position (0, 0), déplacez le pointeur de la quantité indiquée parx
ety
et marquez le carré sur lequel le pointeur se trouve maintenant (sauf si le carré est déjà marqué, auquel cas l'exécution se termine). Ensuite, passez à la lignea
si au moins l'un des carrés directement adjacents est également marqué, et à la ligneb
sinon.Les interprètes sont encouragés à produire le résultat final de la grille sous la forme d'une sorte d'image, de toile, etc.
Complétude de Turing
Draw est Turing-complete car il est possible de compiler une version modifiée (appelée Alternate) d'une machine Minsky dans la langue.
Alternate agit de manière similaire à une machine Minsky à deux compteurs, mais il existe une grande restriction sur les commandes: les commandes doivent alterner entre le ciblage du premier et du deuxième compteur. Pour contourner cette modification, a été ajouté une commande supplémentaire:
nop
. Cette commande ne change pas du tout le compteur ciblé, ce qui permet de "compléter" les modifications consécutives sur un compteur, satisfaisant la restriction décrite ci-dessus. Cela signifie également que le registre à modifier n'a pas à être donné et, pour une instruction donnée, peut être directement déduit des instructions à partir desquelles l'exécution peut y accéder.Exemple: cette machine Minsky
se transforme en ce programme alternatif:
Cette restriction est nécessaire en raison de la façon dont le programme Draw éventuel gère les registres, c'est-à-dire qu'il ne les différencie pas du tout. Au lieu de cela, le programme Draw copie simplement le registre qui n'a pas été modifié par l'instruction précédente, en le modifiant en fonction de l'instruction en cours d'exécution.
Ensuite, le programme alternatif est directement traduit en Draw comme suit:
Le programme démarre avec ce bloc.
inc
,dec
Etnop
sont traduits dans presque la même manière que l'autre. Dans tous les cas, il n'y a pas de différence entre changer le premier ou le deuxième registre (comme expliqué ci-dessus). Voici un incrément, équivalent àinc 2
:Modifiez les nombres dans les
i1_x
parties à l'index de l'instruction en cours, et dans lesi2_x
parties à l'index de la prochaine instruction à exécuter.L'
nop
instruction peut être traduite comme telle:Ceci est un décrément:
i3_x
fait référence à l'instruction à appeler si le compteur est déjà 1.Arrêt:
Changez les étiquettes de manière appropriée et enchaînez tout simplement ensemble. Faire cela pour l'exemple ci-dessus donne le programme Draw dans le référentiel d'en haut.
Interprètes
Il existe actuellement deux interprètes, tous deux écrits en Python. Ils peuvent être trouvés sur le référentiel GitHub de Draw .
lasortie graphique plus facile et dansle mauvais but, en prenant la source via une boîte popup lors du démarrage du script. Golly peut être un peu capricieux avec Python, alors assurez-vous que Python 2 est installé (et ne mélangez pas Golly 32 bits avec Python 64 bits ou vice versa). La sortie est fournie via la grille de cellules intégrée de Golly.L'image suivante est un exemple de sortie du deuxième interpréteur. L'exécution de l'exemple de programme dans le référentiel donne ceci (ou similaire):
la source
-3
Voici l'essentiel.
Mémoire
La mémoire est une carte de bandes, où les clés sont des chaînes et les valeurs sont des entiers de taille arbitraire.
De plus, il existe un ensemble d'étiquettes sur lesquelles le programme peut accéder.
Il y a une pile, qui contient les opérandes, qui sont des chaînes.
Il y a un offest, qui contrôle où dans les bandes de la mémoire il peut accéder.
The One Instruction
-
. Tout d'abord, il sort une chaîneLABEL
de la pile. Si celaLABEL
n'est pas défini comme une étiquette, il définit l'étiquette et efface la source de cette étiquette (c'est-à-dire d'où elle a été poussée) et l'instruction en cours. Sinon, il effectue le calcul suivant, en utilisant les deux premières valeurs,A
etB
:Notez que s'il y a des arguments en excès ou des arguments insuffisants, le programme affichera une erreur, montrant l'état du programme.
Le décalage peut être modifié en accédant à la valeur de
.
.Exemple de code
Cela définit la variable
i
sur7
, en incrémentant les7
temps.Cela multiplie
i+1
par la constante2
.Preuve d'exhaustivité de Turing
Sans tenir compte des tailles int de C ++ (c'est-à-dire, en supposant qu'elles soient infinies), -3 est Turing Complete par réduction à 3-cell brainfuck . Je peux ignorer cette taille car il peut être écrit un interpréteur pour -3 sur un ordinateur avec une mémoire infinie qui a des cellules arbitrairement grandes.
Je crois également que tout BCT peut être écrit en tant que programme -3.
la source