# Programming Computable Functions

En informatique théorique, Programming Computable Functions ou PCF est un langage de programmation théorique apparu pour la première fois en 1977 dans un article de Gordon Plotkin, mais qui est basé sur des notes de Dana S. Scott de 1969 qui n'ont été publiées qu'en 1993. Ce langage consiste en une extension du lambda-calcul simplement typé avec des combinateurs de points fixes et des entiers naturels, ce qui permet de récupérer la complétude au sens de Turing, c'est-à-dire la possibilité d'exprimer n'importe quelle fonction calculable. En effet, l'ajout d'une discipline de types au lambda-calcul, donnant le lambda-calcul simplement typé, limite l'expressivité du langage et les fonctions qui y sont définissables ; l'ajout de combinateurs de point fixe et d'entiers résout ce problème.

## Syntaxe et typage

PCF reprend les types du lambda-calcul simplement typé en y adjoignant un type représentant comme types de base les booléens, $o$, et un type représentant les entiers, $\iota$$^,$. Les types sont donc $o$, $\iota$, ou $\alpha \to \beta$ avec $\alpha$ et $\beta$ des types déjà formés. Ce type représente le type des fonctions de $\alpha$ vers $\beta$. La notation $\alpha \to \beta \to \gamma$ doit être lue comme $\alpha \to (\beta \to \gamma )$.
De plus, la syntaxe de PCF comprend la syntaxe du lambda-calcul simplement typé, et les constructions de base y sont les mêmes : il y a des variables, notées $x,y,z,\dots$ ; si $M$ est un terme de type $\alpha \to \beta$ et $N$ un terme de type $\alpha$, $MN$ est un terme de type $\beta$ qui représente l'évaluation de la fonction $M$ en $N$ ; et si $M$ est un terme de type $\beta$ dans un contexte où la variable $x$ est de type $\alpha$, $\lambda x^{\alpha }.M$ est de type $\alpha \to \beta$ et représente la fonction $x\mapsto M$. Si $M$ est un terme de type $\alpha$, on notera $M:\alpha$. Pour plus de détails, consulter les sections Syntaxe et Règles de typage de l'article sur le lambda-calcul simplement typé.
À cela se rajoutent les constantes propres permettant de manipuler les types de base. Pour chaque entier naturel $n\in \mathbb {N}$, on ajoute une constante ${\underline {n}}:\iota$. De plus, il y a une constante pour chaque booléen, $\operatorname {true} :o$ et $\operatorname {false} :o$. Pour chaque type de base $\sigma$, c'est-à-dire $\iota$ et $o$, on a une constante $\operatorname {if} \ \operatorname {then} \ \operatorname {else} :o\to \sigma \to \sigma \to \sigma$ représentant une instruction conditionnelle : l'idée étant que si $b$ vaut $\operatorname {true}$, l'expression $\operatorname {if} b\operatorname {then} M\operatorname {else} N$vaut $M$, si $b$ vaut $\operatorname {false}$, elle s'évalue en $N$. De plus, il y a deux fonctions pour manipuler les entiers, la fonction successeur $\operatorname {succ} :\iota \to \iota$ et la fonction prédécesseur $\operatorname {pred} :\iota \to \iota$, qui correspondent à ajouter ou soustraire $1$ à leur argument. Enfin, il y a une fonction $\operatorname {zero} ?:\iota \to o$ qui renvoie $\operatorname {true}$ si son argument vaut l'entier ${\underline {0}}$, $\operatorname {false}$ sinon.
Enfin, le principal ingrédient de PCF est sa construction de point fixe : pour chaque type $\alpha$, on dispose d'une constante $Y:(\alpha \to \alpha )\to \alpha$ dont l'interprétation est qu'il renvoie le plus petit point fixe de la fonction qu'on lui passe en argument. Certains auteurs rajoutent à chaque type une constante $\Omega :\alpha$ qui répresente un programme qui ne termine pas. Cette construction n'est pas incluse dans la présentation originelle de Gordon Plotkin, mais peut y être définie comme $Y(\lambda x^{\alpha }.x)$.

## Sémantique opérationnelle

PCF peut être muni d'une sémantique opérationnelle $\to$. Si $M$ et $N$ sont des termes, on a $M\to N$ si $M$ se transforme en $N$ après une étape élémentaire de calcul. On note $M\to ^{*}N$ pour dire que $M$ se transforme en $N$ en zéro ou plusieurs étapes. La relation $\to$ est définie comme suit :
* $(\lambda x^{\alpha }.M)N\to M[x:=N]$ : pour évaluer l'application de la fonction $x\mapsto M$ en $N$, on remplace $x$ par $N$ dans $M$ ;
* $YM\to M(YM)$ : cela exprime que $YM$ est un point fixe de $M$ ;
* $\operatorname {succ} ({\underline {n}})\to {\underline {n+1}}$;
* $\operatorname {pred} ({\underline {n+1}})\to {\underline {n}}$ ;
* $\operatorname {zero} ?({\underline {n}})\to \operatorname {true}$;
* $\operatorname {zero} ?({\underline {n+1}})\to \operatorname {false}$ ;
* $\operatorname {if} \operatorname {true} \operatorname {then} M\operatorname {else} N\to M$ ;
* $\operatorname {if} \operatorname {false} \operatorname {then} M\operatorname {else} N\to N$ ;
* Les règles contextuelles sont les suivantes : si $M\to M'$ alors $MN\to M'N$, $\operatorname {succ} M\to \operatorname {succ} M'$, $\operatorname {pred} M\to \operatorname {pred} M'$, $\operatorname {zero} ?(M)\to \operatorname {zero} ?(M')$ et $\operatorname {if} M\operatorname {then} N\operatorname {else} P\to \operatorname {if} M'\operatorname {then} N\operatorname {else} P$. Elles donnent à PCF une sémantique d'appel par nom.
Cette sémantique est déterministe, c'est-à-dire que si $M\to N$ et $M\to N'$, alors $N=N'$. De plus, elle préserve le typage : si $M\to N$ et que $M$ est de type $\alpha$, alors $N$ aussi.
De plus, on pourrait autoriser la réduction dans tous les contextes, plutôt qu'uniquement dans ceux précisés dans la dernière règle (qui interdit, par exemple, la réduction $NM\to NM'$ avec $M\to M'$ et $N$ qui n'est pas une lambda-abstraction ou $\operatorname {succ}$ ou $\operatorname {pred}$ ou $\operatorname {zero} ?$). Dans ce cas, la réduction obtenue préserve encore le typage et est confluente. De plus, si $M\to ^{*}N$ avec cette réduction, et si $N$ est en forme normale, alors $M\to ^{*}N$ avec la version restreinte. En clair, la sémantique opérationnelle définie ici est standardisante.

### Exemple

PCF permet par exemple de définir des programmes effectuant l'addition de deux entiers. En voici un :
$add:=Y(\lambda f^{\iota \to \iota \to \iota }.\lambda x^{\iota }.\lambda y^{\iota }.\operatorname {if} \operatorname {zero} ?(x)\operatorname {then} y\operatorname {else} \operatorname {succ} (f(\operatorname {pred} x)y))$
Si on note $add'$ la fonction à l'intérieur de $Y$, la somme de deux et trois est calculée par la suite de réductions suivante :
$add~{\underline {2}}~{\underline {3}}\to add'~add~{\underline {2}}~{\underline {3}}\to ^{*}\operatorname {if} \operatorname {zero} ?({\underline {0}})\operatorname {then} {\underline {3}}\operatorname {else} \operatorname {succ} (add(\operatorname {pred} {\underline {2}}){\underline {3}})\to ^{*}\operatorname {succ} (add~{\underline {1}}~{\underline {3}})\to ^{*}$
$\operatorname {succ} (\operatorname {if} \operatorname {zero} ?({\underline {1}})\operatorname {then} {\underline {3}}\operatorname {else} \operatorname {succ} (add(\operatorname {pred} {\underline {1}}){\underline {3}}))\to ^{*}\operatorname {succ} (\operatorname {succ} (add~{\underline {0}}~{\underline {3}}))\to ^{*}$
$\operatorname {succ} (\operatorname {succ} (\operatorname {if} \operatorname {zero} ?({\underline {0}})\operatorname {then} {\underline {3}}\operatorname {else} \operatorname {succ} (add(\operatorname {pred} {\underline {0}}){\underline {3}})))\to ^{*}\operatorname {succ} (\operatorname {succ} ({\underline {3}})))\to ^{*}{\underline {5}}$
Ainsi, $\operatorname {add} ~{\underline {2}}~{\underline {3}}$ se réduit bien en la valeur ${\underline {5}}$.

## Sémantique dénotationnelle

La sémantique opérationnelle présentée plus haut permet de déterminer comment exécuter un terme de PCF comme un programme. Mais pour étudier PCF, il peut être interéssant de traduire un terme comme $\lambda x^{\alpha }.M$ en une fonction au sens mathématique du terme. C'est le rôle de la sémantique dénotationnelle. Mais contrairement au lambda-calcul simplement typé, on ne peut pas interpréter PCF directement dans les fonctions et les ensembles, puisqu'il existe des fonctions qui n'ont pas de point fixe. On va donc interpréter les termes de PCF comme des fonctions continues entre cpo. Un cpo est un ensemble ordonné dans lequel toutes les parties dirigées ont une borne supérieure, et qui possède un plus petit élément. L'intérêt des cpo réside dans ce cas chaque fonction continue possède un plus petit point fixe. La catégorie des cpo est cartésienne fermée.

### Modèle continu

Le modèle continu est l'interprétation usuelle de PCF$^,$. On va définir pour chaque type, chaque contexte et chaque terme une traduction $[\![\cdot ]\!]$ telle que l'interprétation d'un contexte ou d'un type soit un cpo, et si $\Gamma \vdash M:\alpha$ dans PCF, alors $[\![M]\!]:[\![\Gamma ]\!]\to [\![\alpha ]\!]$ est une fonction continue de l'interprétation du contexte vers l'interprétation du type de $M$.
Les types de base sont interprétés comme des domaines plats : on a $[\![\iota ]\!]=\mathbb {N} _{\bot }$ et $[\![o]\!]=\mathbb {B} _{\bot }$, où $\mathbb {N}$ est l'ensemble des entiers naturels, $\mathbb {B}$ l'ensemble des booléens et pour tout ensemble $X$, $X_{\bot }$ est le cpo défini sur l'ensemble $X$ auquel on adjoint un élément $\bot$, avec l'ordre défini par $\bot \leq x$ pour tout $x$, et les éléments de $X$ sont incomparables entre eux. Le type $\alpha \to \beta$ est interprété comme l'ensemble des fonctions continues de $[\![\alpha ]\!]$ vers $[\![\beta ]\!]$. Un contexte $x_{1}:\alpha _{1},\dots ,x_{n}:\alpha _{n}$ est interprété par $[\![\alpha _{1}]\!]\times \dots \times [\![\alpha _{n}]\!]$. On remarque que chaque type est un cpo, donc a un plus petit élément $\bot$.
Considérons maintenant un terme typé et son contexte $\Gamma \vdash M:\alpha$, avec $\Gamma =x_{1}:\alpha _{1},\dots ,x_{n}:\alpha _{n}$.
L'interprétation des constructions issues du lambda-calcul est la suivante :
* $[\![x_{i}]\!]=(x_{1},\dots ,x_{n})\mapsto x_{i}$.
* $[\![\lambda x^{\alpha }.M]\!]=(x_{1},\dots ,x_{n})\mapsto (x\mapsto [\![M]\!](x_{1},\dots ,x_{n},x))$.
* $[\![MN]\!]=(x_{1},\dots ,x_{n})\mapsto [\![M]\!](x_{1},\dots ,x_{n})([\![N]\!](x_{1},\dots ,x_{n}))$.
L'opérateur de point fixe est définie comme suit :
* $[\![Y]\!]$ est la fonction $([\![T]\!]\to [\![T]\!])\to [\![T]\!]$ qui à chaque $f:[\![T]\!]\to [\![T]\!]$ associe son plus petit point fixe. Il est défini comme $\bigvee _{n\in \mathbb {N} }f^{n}(\bot )$, c'est-à-dire comme le supremum de la suite croissante $\bot ,f(\bot ),f(f(\bot )),\dots$.
* Puisque intuitivement, $\Omega =Y(\lambda x.x)$, et que le plus petit point fixe de la fonction identité est $\bot$, $[\![\Omega ]\!]=\bot$.
Les primitives sur les entiers et les booléens sont interprétées comme suit, l'idée étant que $\bot$ représente une valeur non déterminée, par exemple un programme qui ne termine pas :
* $[\![\operatorname {succ} ]\!](n)=n+1$ si $n\in \mathbb {N}$ et $[\![\operatorname {succ} ]\!](\bot )=\bot$.
* $[\![\operatorname {pred} ]\!](n)=n-1$ si $n\in \mathbb {N}$ et $n\neq 0$, $[\![\operatorname {pred} ]\!](0)=\bot$ et $[\![\operatorname {pred} ]\!](\bot )=\bot$.
* $[\![zero?]\!](0)=\operatorname {true}$, $[\![zero?]\!](n)=\operatorname {false}$ si $n\in \mathbb {N}$ et $n\neq 0$, et $[\![zero?]\!](\bot )=\bot$.
* $[\![\operatorname {if} \ \operatorname {then} \ \operatorname {else} ]\!](\operatorname {true} )(x)(y)=x$, $[\![\operatorname {if} \ \operatorname {then} \ \operatorname {else} ]\!](\operatorname {false} )(x)(y)=y$ et $[\![\operatorname {if} \ \operatorname {then} \ \operatorname {else} ]\!](\bot )(x)(y)=y$.

### Modèles standards

Plus généralement, on peut interpréter PCF dans des catégories cartésiennes fermées enrichies dans les cpo. Un tel modèle est appelé modèle standard de PCF. Une catégorie cartésienne fermée enrichie dans les cpo est une catégorie cartésienne fermée ${\mathcal {C}}$ telle que :
* les hom-set ${\mathcal {C}}(A,B)$ sont des cpo pour tous objets $A$ et $B$ ;
* la composition, le pairage et la currification sont continues ;
* l'évaluation et la composition sont strictes : pour tous objets $A$, $B$ et $C$ et tout morphisme $f:A\to B$, si l'on désigne par $\bot _{D}$ le plus petit élément d'un cpo $D$, on a :$\bot _{{\mathcal {C}}(B,C)}\circ f=\bot _{{\mathcal {C}}(A,C)}$, et si l'on désigne par $B\to C$ l'objet des fonctions de $B$ vers $C$ dans la catégorie cartésienne fermée, par $\langle \cdot ,\cdot \rangle$ l'opération de pairage et par $ev_{B,C}:(B\to C)\times B\to C$ le morphisme d'évaluation, on a :
$ev_{A,B}\circ \langle \bot _{{\mathcal {C}}(A,B\to C)},f\rangle =\bot _{{\mathcal {C}}(A,C)}$
* la catégorie possède deux objets $D^{\iota }$ et $D^{o}$ tels que ${\mathcal {C}}(1,D^{\iota })$ soit isomorphe à $\mathbb {N} _{\bot }$ et ${\mathcal {C}}(1,D^{o})$ soit isomorphe à $\mathbb {B} _{\bot }$ en tant que cpo, où $1$ l'objet terminal de la catégorie ${\mathcal {C}}$. Dans la catégorie des cpo, $1$ est l'ensemble à un élément muni de l'égalité comme relation d'ordre.
Dans ce cas, en interprétant dans ${\mathcal {C}}$ les constructions issues du lambda-calcul simplement typé de la façon uselle, en définissant $[\![\Omega ]\!]=\bot$ et $[\![Y]\!]=\bigvee _{n\in \mathbb {N} }[\![\lambda f.f^{n}\Omega ]\!]$ et en interprétant les constructions sur les types primitifs de la même façon que dans le modèle continu en posant $[\![\iota ]\!]=D^{\iota }$ et $[\![o]\!]=D^{o}$, ce qui est rendu possible par les isomorphismes ${\mathcal {C}}(1,D^{\iota })\simeq \mathbb {N} _{\bot }$ et ${\mathcal {C}}(1,D^{o})\simeq \mathbb {B} _{\bot }$, on obtient la sémantique désirée.

## Expressivité
### Turing-complétude

Si $t:\overbrace {\iota \to \iota \to \dots } ^{k}\to \iota$ est un programme dans PCF qui prend $k$ entiers en entrée et renvoie un entier, on peut montrer assez facilement que $t$ détermine une fonction calculable $f:\mathbb {N} ^{k}\to \mathbb {N}$ par $f(n_{1},\dots ,n_{k})=m$ si $f~{\underline {n}}_{1}\dots {\underline {n}}_{k}\to ^{*}{\underline {m}}$ et $f(n_{1},\dots ,n_{k})$ n'est pas définie sinon.
Réciproquement, étant donnée une fonction calculable $f:\mathbb {N} ^{k}\to \mathbb {N}$, on peut se demander si elle est représentée par un terme $t:\overbrace {\iota \to \iota \to \dots } ^{k}\to \iota$ de PCF tel que pour tous entiers $n_{1},\dots ,n_{k}$ et $m$,
$t~{\underline {n}}_{1}\dots {\underline {n}}_{k}\to ^{*}{\underline {m}}\iff f(n_{1},\dots ,n_{k})=m$
Ce problème correspond à la notion de complétude au sens de Turing. La réponse est positive, donc PCF peut représenter toutes les fonctions calculables entre les entiers.
On sait que les fonctions calculables sont obtenues en ajoutant le schéma $\mu$ de minimisation non bornée aux fonctions primitives récursives, et on peut assez facilement montrer que toutes les fonctions primitives récursives sont encodables dans PCF.
Il reste donc à montrer que PCF supporte l'opération de minimisation non bornée : étant donné un terme $f:\iota \to o$, $\mu f:\iota$ est le plus entier $n$ tel que $f~n\to ^{*}\operatorname {true}$ et $f~k\to ^{*}\operatorname {false}$ pour $k<n$ s'il existe, et $\mu f$ ne normalise pas sinon.
Pour cela, on définit $\mu :(\iota \to o)\to \iota$ par $\lambda f^{\iota \to o}.Y(\lambda h^{\iota \to \iota }.\lambda n^{\iota }.\operatorname {if} f~n\operatorname {then} n\operatorname {else} h~(\operatorname {succ} ~n))~{\underline {0}}$. On vérifie facilement que $\mu f$ vérifie bien la propriété désirée.