Informatique et Sciences du Numérique au lycée : un pas plus loin/LANGAGES/Éléments de syntaxe et de sémantique/Éléments de base/Expressions, fonctions et valeurs
Très schématiquement, une exécution d'un programme acquiert des valeurs et transmet, en tant que résultats, des valeurs élaborées à partir de ces entrées. Par exemple, les valeurs peuvent être acquises à partir d'un clavier, à partir de valeurs physiques recueillies par des capteurs, à partir du web ou lues sur des périphériques de stockage, etc. Une valeur peut être un entier, un caractère, un booléen, un fichier, une image, un son, une url, etc. ou une adresse-mémoire. L'origine de ces valeurs peut être très diverse, leur format de transmission peut revêtir de multiples formes mais une fois acquises, les valeurs sont classées en catégories utilisées pour définir leur stockage en mémoire et les opérations qui leur sont applicables. Catégories et opérations sont soit prédéfinies par le langage de programmation utilisé (entiers, addition) ou préalablement définies par l'utilisateur à l'aide des outils fournis par le langage.
Parmi ces outils, le typage est l'un des éléments les plus importants. Le typage le moins contraignant permet au moins de partitionner l'ensemble des valeurs manipulables par un programme, selon la place mémoire qui leur est réservée (entiers sur 32 bits, flottants sur 64 bits par exemple, adresses-mémoire sur 64bits pour la plupart des processeurs). Dans les systèmes de typage un peu plus contraignants, les opérations peuvent elles-mêmes être associées à des types et un algorithme de typage peut vérifier qu'elles ne sont appliquées qu'à des valeurs du type prévu ou accepté comme équivalent au type prévu. Certains systèmes de typage acceptent un type et un seul pour toute entité manipulée par le programme. Cela permet une vérification très forte de la correction du programme : si l'algorithme de typage accepte le programme source, alors l'exécution de celui-ci soit boucle soit s'arrête sur une valeur du type attendu. Dit plus familièrement, un tel système de typage garantit que l'exécution ne conduit jamais au message "Bus error, Core Dump". Ce point est une étape conséquente dans la démonstration de la correction des programmes.
Non seulement les valeurs peuvent être acquises par différentes voies mais elles peuvent être également décrites (on dira dénotées par) par des expressions dans le corps des programmes. Une expression peut être réduite à la description explicite d'une valeur appelée littéral. Par exemple, le littéral 4 dénote l'entier naturel 100 en base 2, le littéral "A" désigne le caractère de code Ascii 65. Une expression peut n'être formée que d'un nom, appelé identificateur, construit conformément aux règles syntaxiques du langage utilisé. En règle générale, un identificateur doit être distinct des mots-clés apparaissant dans les constructions syntaxiques des langages (begin ou end par exemple) et des mots-réservés (par exemple pour permettre l'ajout de nouvelles constructions syntaxiques). Plus généralement, la construction d'une expression est définie par les règles syntaxiques du langage utilisé. Par exemple, x+1
et x+
sont deux expressions reconnues par le langage C.
Il existe une famille de valeurs qui est moins connue, la famille des valeurs fonctionnelles. En mathématiques, une fonction peut être définie par une expression dont le calcul donne la valeur de la fonction en tout point de son domaine de définition (ou espace de départ), disons . Pour cela, il faut choisir un nom, disons , pour désigner un élément quelconque de . Ce nom est appelé variable en mathématiques. L'expression définissant la fonction, disons , est formée à l'aide de noms déjà connus (noms de constantes, d'opérations, de fonctions déjà définies par exemple), de constantes données explicitement et éventuellement de la variable. Pour construire la fonction , on abstrait la variable dans , alors appelé corps de la fonction . Soit appartenant à . Pour calculer , il faut remplacer dans toutes les occurrences de la variable par la valeur . On obtient ainsi une expression notée qui est appelée substitution de la valeur à toutes les occurrences de la variable . Il suffit ensuite de calculer la valeur de l'expression , pour obtenir la valeur de dans l'espace d'arrivée .
En informatique, une valeur fonctionnelle, dite pure, est simplement une fonction au sens mathématique du terme, elle peut être appliquée à une valeur de son espace de départ, valeur dénotée par une expression, pour obtenir une valeur de son espace d'arrivée. Dans les langages typés, ces espaces de départ et d'arrivée sont définis par des types qui eux-mêmes définissent le type de la valeur fonctionnelle. Ainsi la fonction iszero(n) = (n=0)
est de type int -> bool
et l'expression iszero(1)
est évaluée en la valeur false
.
Introduisons un peu de terminologie pour expliquer rapidement la sémantique des identificateurs dans les corps des fonctions. Soit l'expression mathématique . Elle contient quatre identificateurs , , , . Faisons l'abstraction de l'identificateur dans cette expression, devient donc la variable de la fonction et en mathématiques, , , sont souvent appelés les paramètres de la fonction et sont donc supposés connus lorsque l'on applique la fonction à une valeur de . Ils peuvent rester indéterminés quand on étudie par exemple les zéros (ou racines) de en fonction des valeurs possibles de ces paramètres. Mais on étudie alors en réalité une famille de fonctions, chaque fonction de la famille étant définie de manière unique par le choix de ses paramètres. En informatique, les dénominations changent. Lorsque l'on abstrait dans l'expression, il devient le paramètre formel de la fonction . Les identificateurs , , sont, quant à eux, appelés variables libres (ou globales) de la fonction . La valeur de à laquelle est appliquée la fonction est encore appelée argument mais elle est aussi souvent désignée par le terme paramètre effectif. Le résultat de cette application est calculé par substitution de la valeur du paramètre effectif à toutes les occurrences du paramètre formel dans le corps de la fonction. Encore faut-il connaître les valeurs des variables libres de cette fonction pour pouvoir effectuer le calcul. Cela peut être un peu plus compliqué qu'on ne l'imagine et c'est la sémantique du langage qui permettra de définir où trouver ces valeurs.
Une valeur fonctionnelle, appelée fermeture, doit donc contenir (ou avoir accès à) le code de la fonction ainsi que les valeurs des identificateurs et opérateurs libres dans son corps par la construction de la fonction. Cette notion de fermeture est précisée dans la section Déclarations puis généralisée dans la section Instructions et procédures pour rendre compte des notions de procédure et méthode. Notons que certains langages de programmation autorisent le passage de valeurs fonctionnelles en argument et l'obtention de fermetures comme résultats. Cela permet d'écrire des fonctions décrivant un traitement commun à des situations qui ne sont pas identiques. Les traitements spécialisés des parties différentes peuvent alors être fournis comme arguments, sous forme de valeurs fonctionnelles, à la fonction de traitement général.
Les fonctions en mathématiques peuvent être partielles, c'est-à-dire qu'elles ne sont pas définies en certains points de l'ensemble de départ. C'est le cas pour la fonction tangente, considérée informellement comme de domaine bien que non définie en tous points multiples de .
En informatique, une fonction doit être une fonction totale (partout définie). Il faut comprendre par là que toute valeur du domaine peut être a priori choisie comme argument même si cette valeur "ne doit jamais arriver". Si on souhaite apporter des restrictions sur certaines valeurs de l'ensemble de départ, il faut décrire un traitement explicite pour ces valeurs par exemple en utilisant des exceptions .