En décrivant ce qu'est une fonction, on décrit un premier genre de variable locale que sont les variables muettes de la fonction.
A titre d'exemple, considérons un langage `a,b,s("."), f(".,."), g(".,.,."),k("...")`
On définit une fonction `"|"` appelé constructeur de fonction. Il prend en premier argument une séquence de variables muettes distinctes et en second argument un programme écrit dans le langage augmenté des variables muettes, qui peuvent venir masquer des variables de même noms déjà existantes. Et on le munie d'une syntaxe centrée de priorité plus faible que la virgule, le transformant ainsi en un opérateur. Par exemple :
`x,y "|" f(f(a,y),x)`
L'opérateur `"|"` appliqué à la séquence de variables muettes `x,y,z` et au terme ` f(f(a,y),x)` produit la fonction correspondante. Autrement dit ce terme est un programme, que l'on peut appliquer directement à 2 arguments `(u,v)` :
`(x,y"|"f(f(a,y),x))(u,v) ↬ f(f(a,v),u)`
Vous remarquerez que le premier membre définit 2 nouvelle variables libres `x,y` dont la portée s'étend sur le corps de la fonction. Il y a donc un contexte propre au corps de la fontion qui contient un langage enrichie de ces 2 variables supplémentaires. La fonction `"|"` prend comme premier argument une séquence composée de variables, et elle n'évalue pas ces variables, elle prend seulement leur nom qu'elle rajoute au contexte comme nouvelles variables, masquant les variables de même noms déjà référencées dans le contexte, pour former un nouveau contexte dont la portée s'arrête au second membre appelé le corps de la fonction. Notez que la fonction ainsi produite peut s'appliquer à un terme contenant des variables de même noms que celles utilisé dans l'appel, sans que cela n'ait d'importance, car les variables d'appel sont muette, ce sont de nouvelles variables libres.
La fonction ainsi définie est d'arité fixe, égale à 2. Cela a pour conséquence que appliquée à une séquence de taille différente, la fonction retourne `sf"nada"`. On peut proposer un autre comportement, en spécifiant des valeurs par défauts des derniers arguments. Exemple :
`x, y "=" s(a) "|" f(f(a,y),x)`
L'opérateur d'égalité est de priorité syntaxique plus forte que celle de la virgule. La fonction ainsi construite est d'arité 1 ou 2. Elle s'applique nécessairement à un premier membre désigné par la variable muette `x` car ce membre n'a pas de valeur par défaut. Le membres suivant dans l'appel peut être omis car il a une valeur par défaut.
Etant donné une variable `z`. Notez que la fonction nullaire `() "|" z` n'est pas identique au terme `z`. En effet, l'évaluation de `z()` va exécuter le programme contenue dans la variable `z` en ne prenant aucun argument, tandis que `(() "|" z)()` est égale à `z`. Si la variable `z` est libre, l'évaluation de `z()` donnera le terme `z()` et non le terme `z`.
Nous avons une notation plus explicite, où figure la déclaration des variables muettes :
`AAx, x "↦" f(x,x)`
Et où le meta-opérateur `"↦"` est un simple opérateur de construction de couple, construisant une arrête appartenant au graphe de la fonction que l'on définit. La méta-opération est transférée à l'opérateur de déclaration de variable universelle `AA` qui prend en argument une liste de nouvelles variables dont la portée s'étend au corps de la fonction, c'est à dire au bloc où se trouve cette déclaration. Ainsi ce terme désigne un ensemble d'arrêtes définissant le graphe d'une fonction, et ainsi définie une fonction sans lui donner de nom. On peut alors appliquer cette fonction à l'entrée `u` :
`(AAx, x"↦"f(x,x)) (u) "↦" f(u,u)`
On perfectionne la définition de fonction. Le premier membre de l'opérateur de construction de fonction, devient un terme quelconque appelé la tête de la fonction, devant contenir toutes les variables déclarées universellement, tandis que le second membre est appelé le corps de la fonction. Cela restreint le domaine de définition aux seuls termes qui s'unifient avec la tête de la fonction. Exemple :
`AA(x,y), (x,f(x,x),f(a, y))"↦"g(x,y,b)`
Cela définit une fonction qui appliquée à `b,f(b,b),f(a,s(a))` retourne `g(b,s(a),b)`. En revanche appliqué à `a,f(a,b),f(a,a)`, elle retourne `sf"nada"` qui indique que l'on applique la fonction en dehors de son domaine de définition.
On définit une fonction par morceau par une séquence de fonctions. Exemple de fonction définie en trois morceaux :
`AA(x,y)`
`(s(x),y)|->f(x,y)`
`(x,s(y))|->g(x,y,x)`
`(x,y)|->g(x,x,y)`
Le passage à la ligne correspond à un opérateur de priorité syntaxique plus faible. Par défaut, la fonction va utiliser la première sous-fonction qui marche c'est à dire qui aboutit à un résultat autre que `sf"nada"`. On peut également par le même procédé définir des fonctions ayant plusieurs arités. Exemple :
`AA(x,y)`
`s(x)|->f(x,x)`
`(s(x),y)|->f(x,y)`
`(x,y,a)|->f(y,x)`
Cette fonction est suceptible de prendre 1 ou 2 ou 3 arguments.
`AA(x,"*"u,"*"v)`
`(x,x)|->f(x,y)`
`(x,h("*"u),"*"v)|->f(g(x,"*"v),"*"u)`
`(x,"*"u)|->"*"u`
Cette fonction est suceptible de prendre 2 ou plus d'arguments.
On définit un ensemble générique par une entête déclarant de nouvelle variables suivie par un terme. Exemple :
`E = ( AA(x,y), alpha(x,alpha(x,y)) )`
On définit un ensemble générique par morceau, par une entête déclarant de nouvelle variables suivie par une séquence de termes. Exemple :
`E = ( AA(x,y), alpha(x,alpha(x,y)), y(x), alpha(x) )`
Les ensembles génériques par morceau sont implémentés pareillement que les fonctions unaires par morceau. Elle correspondent à des fonctions d'arité de sortie nulle qui appliqué à un terme ne retourne que l'éventuelle exception, vrai ou faux, selon que l'unification à réussie ou non. Et elle constitue la fonction caractéristique de l'ensemble.
L'instruction `sf"var" x` déclare une nouvelle variable de nom `x` initalement libre. Elle est ajoutée au langage en cours. Et s'il existe déjà une variable de même nom, alors celle-ci est masquée par la nouvelle variable. La variable qui vient juste d'être masquée par `x` se note `"↑"x` et celle-ci peut masquer une autre variable de même nom qui se note alors `"↑↑"x` et ainsi du suite.
Néanmoins on ne crée pas un contexte après chacune de ses instructions. On définie un contexte seulement pour chaque bloc de code comprenant de telles instructions indépendament du lieu où elles sont placés dans le bloc de code.
Les définitions de fonction et d'ensemble générique vu précédement sont des blocs de code avec déclaration de variable. L'instruction `AAx,` se comporte comme l'instruction `sf"var" x` en activant en plus un mécanisme fonctionnel définissant les fonctions par morceau et les ensembles génériques.
L'utilisation d'une variable `y` non déclarée dans le bloc pourra selon les cironstances hériter du bloc parent (héritage statique) ou du bloc appelant (héritage dynamique).
On s'inspire d'un travail précédent https://vulgate.toile-libre.org/Informatique/Interpreteur.htm
---- 30 juin 2025 ----