![]()
![]()
![]()
![]()
![]()
Next: Ordre d'évaluation de Scheme Up: Premiers pas Previous: Les outils   Contents   Index
Subsections
- Les fonctions
- Les booléens
- Les caractères
- Les erreurs
- Les chaînes de caractères
- Les nombres
- L'alternative
- Affichage
- Abstraire en nommant
- Abstraire par les fonctions
Premiers pas... Dans cette section, nous allons examiner quelques concepts de base du langage, comme les fonctions, les types de données primitifs, la gestion des erreurs et l'alternative.
Les fonctionsAvant de décrire succinctement les différents types de donnée de Scheme, introduisons les fonctions. Une fonction est un objet qui peut être appliqué à des arguments. Par exemple, on écrira :
Osm> (+ 1 2) => 3qui signifie appliquer la fonction + aux arguments 1 et 2. On remarquera que Scheme utilise la notation infixe, ce qui signifie que l'opérateur est placé en premier. Cela procure au langage, on le verra, une grande homogénéité dans l'écriture des programmes.
En Scheme, les fonctions peuvent avoir 0, 1 ou plusieurs arguments. Certaines fonctions ont un nombre fixé d'arguments, d'autres ont un nombre variable d'arguments. C'est le cas de la fonction + qui permet les écritures :
Osm> (+) => 0 Osm> (+ 1) => 1 Osm> (+ 1 2 3 4 5 6 7 8 9) => 45Nous verrons plus tard comme définir nos propres fonctions, avec un nombre d'arguments fixe ou variable.
Les booléensLes booléens sont en général le résultat des comparaisons. En Scheme, ``vrai'' s'écrit #t (pour true) et ``faux'' s'écrit #f (pour false). Se sont les deux seules valeurs possibles pour les booléens. Faisons un peu d'arithmétique binaire à l'aide des opérateurs booléens :
Osm> (and #t #t) => #t Osm> (and #t #t #f #t) => #f Osm> (or #t #f #t) => #t Osm> (not #t) => #f Osm> (not #f) => #t Osm> (boolean? #t) => #t Osm> (boolean? 1) => #fAvec ces exemples, on remarque que and et or sont des fonctions avec un nombre d'arguments variable. Quant à not, elle n'accepte qu'un seul argument.
Nous introduisons aussi la notion de prédicat. Ces fonctions retournent un booléen et permettent de savoir si l'argument est d'un certain type. Ainsi la fonction boolean? retourne ``vrai'' si son argument est #t ou #f, et ``faux '' dans les autres cas. Tous les types de base de Scheme sont associés à un prédicat. Par convention, le nom des fonctions retournant un booléen se termine par un point d'interrogation.
Les caractèresLes caractères s'écrivent
#\xoù x est le caractère souhaité. Par exemple, le caractère `a' s'écrit en Scheme#\a.Nous pouvons écrire :
Osm> (char? #\a) => #t Osm> (char=? #\a #\A) => #f Osm> (char-ci=? #\x #\X) => #tLes caractères peuvent principalement être comparés et convertis. La fonction char=? compare deux caractères, en tenant compte de la casse (majuscule, minuscule), alors que char-ci=? est insensible à la casse.
Dans le RxRS[3] sont décrites toutes les autres fonctions relatives aux caractères.
Les erreursQue se passe-t-il si nous tapons
(char=? 1 #\a)? Il devrait nécessairement y avoir une erreur signalée parce que la fonction char=? attend deux caractères et elle est appliquée à un entier et un caractère.Eh bien cette écriture provoque une erreur de la forme :
Osm> (char=? 1 #\a) => Error : wait a character instead of `1' in `(char=? 1 #\a)'.Cette erreur conduit à l'abandon de tout ce que l'interprète était en train de faire et le retour à l'invite. Notons toutefois que la forme du message d'erreur dépend de l'interprète utilisé.
Les chaînes de caractèresLes chaînes de caractères s'écrivent entre guillemets. Il existe un certain nombre de fonctions pour les manipuler :
Osm> "une-chaîne" => une-chaîne Osm> (string #\a #\b #\c) => abc Osm> (string-set! "abc" 0 #\X) => Xbc Osm> (string-ref "abc" 2) => #\c Osm> (string-set ! "ac" 2 #\Z) => Error: index `3' out of range in `(string-set! "ac" 3 #\Z)' Osm> (string=? "abc" "ABC") => #f Osm> (string-ci=? "abc" "ABC") => #t Osm> (string? (string #\a #\b #\c)) => #tLe dernier exemple montre que les appels aux fonctions peuvent être imbriqués. C'est en fait vrai pour toutes les expressions Scheme, comme nous aurons l'occasion de le voir.
Les nombresLes nombres s'écrivent pour la plupart naturellement : l'entier 1 s`écrit 1, le nombre réel 1.23 s'écrit 1.23. Scheme propose d'autres syntaxes plus ésotériques comme par exemple #b1001 qui représente l'entier binaire 9.
Comme nous le verrons plus loin, Scheme définit une tour des types numériques. Cette spécification lui permet de toujours donner le ``meilleur'' résultat possible. Ainsi, l'entier 4 divisé par l'entier 3 ne donne pas l'entier 1, comme c'est le cas avec la plupart des autres langages, mais le nombre rationnel 4/3. Ainsi, en Scheme, (4/3)*3 ne s'évalue pas en 3, mais en 4, ce qui est le résultat exact. Vérifions :
Osm> (* (/ 4 3) 3) => 4 Osm> (/ 4 3) => 4/3Lorsque l'on dit que Scheme donne toujours un résultat le plus exact possible, vérifions-le encore avec :
Osm> (* 9999999 9999999 9999999 9999999) => 9999996000000599999960000001Cette fois-ci, le résultat a été converti en entier long. Peu de langages sont si soucieux de l'exactitude des résultats, n'est-ce pas ?
L'alternativeL'alternative permet d'effectuer un choix en fonction d'un prédicat. En Scheme, l'alternative s'écrit (if condition alors sinon), où condition, alors, sinon sont des expressions Scheme. La clause sinon peut être omise. Nous pourrions avoir :
Osm> (if #t 1 2) => 1 Osm> (if #f 1 2) => 2 Osm> (if #f 1) => #unspecifiedLa première écriture peut être lue comme ``si vrai alors retourner 1 sinon, retourner 2''.
Notons qu'en Scheme, toutes les valeurs sont supposées vraies, à l'exception de #f. Ceci est une entorse à l'orthogonalité du langage, mais rend, en pratique, l'écriture bien plus lisible. Nous pouvons donc écrire :
Osm> (if 1 3 4) => 3 Osm> (if (not "e") #\a #\b) => #\b
AffichageIl existe en Scheme une fonction bien pratique : display permet d'afficher tous les objets existants. C'est une fonction dont le paramètre est l'objet à afficher. Par exemple :
Osm> (display 123) => 123#unspecified123 est l'affichage produit par display. #unspecified est sa valeur de retour.
Pour aller à la ligne après avoir affiché une valeur, on pourra utiliser la fonction newline, comme dans :
Osm> (display #t) (newline) => #t #unspecifiedou bien :
Osm> (display "1234") (newline) => 1234 #unspecifiedRemarquons qu'un entier et une chaîne ne contenant que des chiffres s'affichent de la même manière.
De plus, display est une fonction qui peut prendre des valeurs de n'importe quel type. Nous l'avons illustré avec un entier, un booléen et une chaîne de caractères. Elle sera donc appelée fonction polymorphe.
Abstraire en nommantTout langage de programmation permet de donner des noms à des résultats. Sans ce procédé, il serait fastidieux de programmer, car on serait sans cesse obligé de répéter les expressions. C'est la première possibilité d'abstraction d'un langage.
Nommer en Scheme se fait à l'aide de la fonction define :
Osm> (define un-nom 123) => #unspecifiedIci, un-nom est le nom que l'on souhaite définir ; c'est un symbole. 123 est la valeur de définition.
En Scheme, tous les caractères imprimables mis à par les ``blancs'' peuvent être utilisés dans un nom, pour peu qu'il commence par une lettre. Scheme ne fait pas la différence entre les majuscules et les minuscules dans les symboles : il est insensible à la casse.
La valeur de retour de define est une valeur spéciale qui signifie qu'elle n'est pas spécifiée. Comme Scheme est un langage fonctionnel, l'évaluation de toutes les expressions doit avoir un résultat. Cependant, dans certain cas dont celui-ci, la valeur de retour n'est pas spécifiée ; #unspecified est alors retourné !
Comment vérifier que un-nom ``vaut'' maintenant 123 ? Entrons :
Osm> un-nom => 123Que se passe-t-il si on demande la valeur d'un symbole sans l'avoir défini :
Osm> non-définit => Error: symbol `non-définit' is unbounded in `non-définit'.La réponse est claire : Scheme n'accepte pas que l'on évalue des noms sans les avoir préalablement définis.
Abstraire par les fonctionsDans cette section, nous allons apprendre à définir nos propres fonctions. Cette possibilité est très puissante car elle permet d'augmenter sans limite le nombre des fonctions offertes par le langage.
La forme define est aussi utilisée pour définir les fonctions, en utilisant la syntaxe suivante :
(define (nom param-1 param-2 ... param-m) expression-1 expression-2 expression-n)Ici, nom, param-1, param-2, ..., param-m sont des symboles et expression-1, expression-2, ..., expression-n sont des expressions Scheme.
Cette écriture crée une nouvelle fonction dont le nom est nom. Cette nouvelle fonction a m paramètres. Elle aurait tout aussi bien pu n'avoir aucun paramètre. Lorsque l'on applique cette fonction à des arguments, les paramètres prennent la valeur des arguments, puis, les expressions sont évaluées leur ordre d'écriture. La valeur retournée par la fonction est la valeur de retour de la dernière expression. L'ensemble des expressions forme le corps de la nouvelle fonction.
Définissons une fonction qui retourne la somme de ses deux arguments en les ayant préalablement affiché à l'écran :
Osm> (define (somme a b) (display "argument 1 = ") (display a) (newline) (display "argument 2 = ") (display b) (newline) (+ a b)) => #unspecifiedL'affichage de #unspecified nous indique que la fonction somme a bien été enregistrée. Nous pouvons donc maintenant l'appliquer à des arguments :
Osm> (somme 3 4) => argument 1 = 3 argument 2 = 4 7Nous obtenons bien ce que nous pressentions. Essayons un appel composé :
Osm> (somme 3 (somme 5 6)) => argument 1 = 5 argument 2 = 6 argument 1 = 3 argument 2 = 11 14Cet exemple est très intéressant car il montre la manière dont fonctionne l'interprète Scheme.
Nous appliquons somme à deux arguments, 3 et (somme 5 6). Pour évaluer cette application, l'interprète évalue les trois composantes de cette application, c'est-à-dire le symbole somme, l'entier 3 et l'expression (somme 4 5). L'évaluation du symbole somme retourne la fonction que nous avons définie, l'évaluation de l'entier 3 donne l'entier 3. Enfin, l'évaluation de (somme 5 6) retourne l'entier 11. Mais pour obtenir ce dernier résultat, l'interprète a du évaluer au préalable (somme 5 6) qui se décompose en l'évaluation de somme, de 5 et de 6. Cette sous-évaluation provoque l'affichage des deux premières lignes et retourne l'entier 11. Maintenant que l'interprète dispose des composantes de la première application, il l'évalue, ce qui provoque l'affichage des deux dernières lignes et retourne l'entier 14.
Les affichages effectués avec les fonctions display et newline nous permettent de connaître le fonctionnement de Scheme. Ce sont des fonctions à effets de bord, c'est-à-dire qu'elle modifient l'état du système, l'écran en l'occurrence.
![]()
![]()
![]()
![]()
![]()
Next: Ordre d'évaluation de Scheme Up: Premiers pas Previous: Les outils   Contents   Index © 1993 to 2001 Erian Concept