Théorème 1Calculabilité
Les fonctions récursives sont calculables par machine
Toute fonction récursive est calculable par une machine à registres : il existe un programme tel que pour tout .
Démonstration
Trois faits. Disons qu'un programme mentionne les registres qui figurent dans ses instructions.
(a) Localité. Un programme ne modifie que les registres qu'il mentionne, et son calcul ne dépend que de leur contenu : c'est vrai d'une étape, donc de toutes, par récurrence.
(b) Renommage. Si est une injection de dans , le programme , où chaque registre est remplacé par , fait sur les registres exactement ce que fait sur les registres .
(c) Enchaînement. Soit et de longueurs et . Le programme s'obtient en remplaçant, dans , tout saut vers un numéro par un saut vers , puis en écrivant à la suite , dont chaque saut vers devient un saut vers . Son calcul est celui de , suivi, si s'arrête, de celui de à partir de la configuration atteinte ; il s'arrête si et seulement si les deux s'arrêtent.
Macro-instructions. Dans un programme, on réserve un registre que rien n'incrémente et qui vaut donc toujours ; alors est un saut inconditionnel vers . Avec lui, on écrit des programmes, enchaînés par (c) :
, qui vide en le décrémentant jusqu'à ;
, qui ajoute le contenu de à et vide , par une boucle qui décrémente et incrémente ;
, qui place dans le contenu de sans changer celui-ci : on vide et un registre auxiliaire , on transfère à la fois dans et dans , puis dans .
Appel. Soit un programme qui calcule et ne mentionne que des registres d'indices inférieurs à , avec . Pour des registres et et un décalage , l'appel vide les registres , copie dans pour , exécute renommé par , puis copie dans .
Par (a) et (b), le programme renommé opère sur le bloc comme sur une configuration initiale : l'appel s'arrête si et seulement si est défini, et place alors cette valeur dans . On choisit toujours , et au-delà de tous les registres qui portent des données, les registres et distincts entre eux et hors du bloc , si bien qu'un appel ne modifie que et des registres auxiliaires.
Récurrence sur les fonctions récursives. L'ensemble des fonctions partielles calculables par machine contient les fonctions de base et il est stable par les trois opérations ; il contient donc toutes les fonctions récursives.
Base. Le programme vide calcule , puisque vaut au départ. suivi de calcule , et calcule .
Composition. Pour , on enchaîne les appels qui placent dans des registres neufs , puis l'appel qui place dans . Si l'un des n'est pas défini, ou si ne l'est pas en , l'appel correspondant ne s'arrête pas.
Récurrence primitive. Pour et , avec dans , on place d'abord dans un registre neuf .
Puis, tant que trouve non nul, on place dans un registre neuf , on vide , on transfère dans et l'on incrémente un compteur , initialement nul ; enfin on transfère dans .
Au début du tour de rang , compté à partir de , et , par récurrence sur ; la boucle fait tours. Sans paramètre, on place d'abord l'entier dans par instructions .
Minimisation. Pour : on place dans un registre neuf ; si trouve nul, on transfère dans et l'on s'arrête ; sinon on incrémente et l'on recommence. Le calcul s'arrête si et seulement si sont définis, les premiers non nuls et le dernier nul, et il rend alors : c'est exactement la définition de la minimisation.
□La preuve est celle d'un compilateur : chaque opération de construction d'une fonction récursive se traduit en un morceau de programme, et l'appel joue le rôle d'un sous-programme, dont les registres de travail sont tenus à l'écart de ceux de l'appelant. Le seul point délicat est cette séparation, qui repose sur la localité (a).
La réciproque, objet du nœud Kleene, demande de coder les programmes et leurs calculs par des entiers ; les deux sens ensemble montrent que les deux définitions de la calculabilité coïncident.