Programme comme donnée — calculabilité et indécidabilité
Introduction
Vous avez écrit du code toute l'année. Il est temps de regarder le code lui-même comme une donnée : un texte qu'un autre programme peut lire, analyser, exécuter, transformer. Cette idée — anodine en apparence — fonde toute l'informatique théorique, et débouche sur l'un de ses résultats les plus profonds : certains problèmes parfaitement définis n'admettent aucun programme qui les résout. C'est le contenu de l'item .
Le cœur de ce que vous allez voir est un cousin algorithmique du paradoxe du menteur (« cette phrase est fausse » : si elle est vraie, elle est fausse ; si elle est fausse, elle est vraie). L'auteur de la démonstration, Alan Turing, est aussi celui dont le film The Imitation Game (2014) retrace la contribution au déchiffrement d'Enigma pendant la Seconde Guerre mondiale — mais ses idées sur le calcul, formulées dès 1936, lui survivent encore plus largement.
Un programme est une donnée
Quand vous tapez python mon_script.py, voici ce qui se passe : le programme
CPython (l'interpréteur Python, lui-même écrit en C) lit votre fichier
mon_script.py, le parse en une structure de données interne (un arbre
syntaxique), puis l'exécute. Votre script n'est pas magique — c'est une
chaîne de caractères, lue comme telle par un autre programme.
| Outil | Rôle | Exemple |
|---|---|---|
| Interpréteur | Lit le code et l'exécute directement. | CPython, navigateur (JS). |
| Compilateur | Traduit le code en un autre langage (souvent du natif). | GCC pour le C, javac pour Java. |
| Transpileur | Traduit d'un langage source vers un autre langage source. | TypeScript → JavaScript. |
.py comme un humain lirait un livre. Le code que vous écrivez est la
donnée d'entrée de CPython.Calculabilité — ce qui peut être calculé
Une fonction est dite calculable s'il existe un algorithme (donc un programme, dans n'importe quel langage Turing-complet) qui la calcule en un nombre fini d'étapes pour toute entrée.
Thèse de Church-Turing (énoncé informel) : la classe des fonctions calculables est la même pour tous les modèles de calcul raisonnables — machine de Turing, λ-calcul, Python, C, JavaScript. Le choix du langage ne change pas ce qui est calculable, seulement la commodité d'écriture.
Calculabilité dépend-elle du langage utilisé ?
Le problème de l'arrêt — l'énoncé
Voici une question simple en apparence :
Existe-t-il un programme
arret(p, e)qui, étant donné un programmepet une entréee, répond toujours parTruesi l'exécution depsuretermine, et parFalsesinon ?
Un tel programme serait précieux : il détecterait toutes les boucles infinies avant exécution. Hélas, un tel programme n'existe pas. Le problème de l'arrêt est indécidable.
La preuve par auto-référence
L'argument est dû à Alan Turing (1936). Il procède par l'absurde et exploite le fait qu'un programme est une donnée pour un autre programme.
Supposons qu'une fonction arret(p, e) existe, qui termine toujours et
répond correctement à la question : « le programme p exécuté sur e
termine-t-il ? ».
Construisons alors la fonction suivante :
def paradox(p):
if arret(p, p): # si p appliqué à p termine…
while True: # …alors paradox boucle pour toujours.
pass
else: # sinon (p sur p ne termine pas)…
return # …paradox termine immédiatement.
Le code de paradox est un programme Python parfaitement bien défini, à
condition que arret existe. Posons-nous la question fatidique :
Que se passe-t-il quand on exécute paradox(paradox) ?
Deux cas possibles, et les deux mènent à une contradiction :
- Si
paradox(paradox)termine : alors par définition deparadox, c'est quearret(paradox, paradox)a retournéFalse. Maisarretest censé être correcte — doncparadox(paradox)ne termine pas. Contradiction. - Si
paradox(paradox)ne termine pas : alors par définition deparadox, c'est quearret(paradox, paradox)a retournéTrue. Maisarretest censé être correcte — doncparadox(paradox)termine bien. Contradiction.
L'hypothèse de départ (l'existence de arret) conduit à une contradiction
dans tous les cas. Cette hypothèse est donc fausse. Aucun programme
arret ne peut exister.
arret ce qui va lui arriver à lui-même, puis fait l'inverse —
exactement le mécanisme du paradoxe du menteur, transposé en code. C'est la
même idée que dans la preuve de Cantor sur la non-dénombrabilité de
. Le procédé est appelé auto-référence ou argument
diagonal.Le problème de l'arrêt est indécidable signifie que…
Conséquences
L'indécidabilité du problème de l'arrêt n'est pas une limite technique qu'on lèvera demain avec un meilleur compilateur. C'est une limite mathématique, démontrée, universelle. Elle a des cousines :
- Indécidabilité de l'équivalence : on ne peut pas écrire un programme qui décide si deux programmes calculent la même fonction.
- Théorème de Rice (1953) : toute propriété non-triviale de la fonction calculée par un programme est indécidable.
Cela dit, les outils approchés existent : analyseurs statiques (mypy,
pylint), démonstrateurs (Coq, Lean), vérification de modèles. Ils ne
résolvent pas le problème de l'arrêt en général, mais répondent
correctement sur les cas qu'ils savent traiter — et refusent de
répondre ailleurs.
Pour aller plus loin
Le résultat de Turing (1936) a précédé l'existence des ordinateurs. Il fonde l'informatique théorique : ce que vous lisez sur le problème P vs NP, sur les machines quantiques, sur la cryptographie, repose sur cette distinction entre ce qui peut être calculé et ce qui ne le peut pas. Le programme officiel s'arrête à l'argument informel — mais vous avez vu l'essentiel.