Programmation Scheme/Grammaire de base
La base de la programmation Scheme est la définition de procédures.
Une procédure de base est de la forme
(opération_primitive expression1 expression2 … expression_n)
où opération_primitive est une procédure prédéfinie. À la place d'une opération primitive, on peut aussi utiliser une procédure définie préalablement.
Les arguments de la procédures sont écrits les uns à la suite des autres, séparés par un ou plusieurs espaces, voire même des sauts de ligne. Ce sont des expressions qui peuvent être des constantes, des variables ou elles-mêmes des procédures.
Quelques opérations primitives
[modifier | modifier le wikicode]Pour quitter l'interpréteur Scheme, il faut taper (exit).
Opérations sur les nombres
[modifier | modifier le wikicode]+: addition ;-: soustraction ;/: division ;expt: élévation à la puissance (n'admet que deux expressions en argument) ;(expt a b)calcule a b ;sqrt: racine carrée (une seule expression) ;abs: valeur absolue (une expression) ;sin,cos,tan: fonctions trigonométriques (une expression) ;
asin,acos,atan: leurs fonctions réciproques (une expression) ;log: logarithme néperien (une expression) ;exp: exponentielle (une expression).
On remarque de fait que Scheme utilise la notation préfixée (parfois appelée « notation polonaise », bien que celle-ci soit sans parenthèse). Par exemple, l'expression infixée « 1+2+3 » donne, en notation préfixée, « (+ 1 2 3) ».
Notons également que 1/7 désigne la fraction formelle ; pour effectuer l'opération, il faut écrire (/ 1 7) (le résultat étant… 1/7).
Opérations sur les listes
[modifier | modifier le wikicode]quote: indique explicitement que l'objet est une liste (en cas de confusion possible, notamment lorsque le premier objet est une lettre ou une opération primitive) ;(quote (expression1 … expression_n))est abrégé en'(expression1 … expression_n)(la parenthèse ouvrante est précédée par une apostrophe) ;car: retourne le premier élément d'une liste ;cdr: retourne la liste amputée du premier élément ;cons: construit une liste à partir de deux expressions dont la deuxième est une liste ;list: construit une liste à partir d'un nombre arbitraire d'expressions.
- Exemples
(cons 'a '(b)) ⇒ (a b)
(list 'a 'b) ⇒ (a b)
(car '(a b)) ⇒ a (cdr '(a b)) ⇒ (b)
Si l'on utilise cons et que le deuxième élément n'est pas une liste, cela crée alors une « liste pointée »
(cons 'a 'b) ⇒ (a . b)
(cons 'a '(b)) ⇒ (a b)
(cons '(a) 'b) ⇒ ((a) . b)
En fait, cons construit des paires (cf infra), et le second élément de la paire n'est pas nécessairement une liste.
L'opération car sur liste pointée renvoie l'élément à la gauche du point, cdr renvoie l'élément à la droite du point.
Opérations sur les variables
[modifier | modifier le wikicode]Pour mettre une expression expr dans une variable var, on utilise define :
(define var expr)
en notation « infixée », cela revient à écrire « var = expr ».
Soit une expression expr contenant des variables var1, var2, … , var_n. Pour mettre cette expression dans une variable fct et en faire une fonction, on utilise aussi define :
(define (fct var1 … var_n) expr)
Cela revient à écrire, en notation infixée :
- fct(var1, …, var_n) = expr
Pour l'évaluer en attribuant des valeurs constantes cst1, cst2, …, cst_n à ces variables (c'est-à-dire en notation infixée calculer fct(cst1, cst2, …, cst_n)), on écrit :
(fct cst1 … cst_n)
Structures de contrôle
[modifier | modifier le wikicode]Exécution conditionnelle
[modifier | modifier le wikicode]L'exécution conditionnelle se fait avec l'opération primitive if. Dans l'expression
(if booléen expr)
alors l'expression expr est éxecutée si booléen est vrai (#t), elle n'est pas exécutée sinon. Ainsi
(if #t '(a)) ⇒ (a) (if #f '(a)) ⇒
Si l'on met deux expressions (if booléen expr1 expr2), alors expr1 est évaluée si booléen est vrai et expr2 est évaluée si booléen est faux — cela équivaut, en langage infixé, à « if booléen then expr1 else expr2 ». Ainsi
(if #t '(a) '(b)) ⇒ (a) (if #f '(a) '(b)) ⇒ (b)
Bien sûr, tel quel, cela ne présente d'intérêt que si booléen est une expression dont l'évaluation donne un booléen. Les opérations primitives donnant des booléens sont appelées « prédicats » (voir ci-après).
On peut aussi utiliser l'opération perimitive cond ; celle-ci admet plusieurs booléens :
(cond (booléen1 expr1) (booléen2 expr2) … (booléen_n expr_n) (else expr_sinon))
L'expression expr1 est évaluée si booléen1 est #t, expr2 est évaluée si booléen2 est #t, …, expr_n est évaluée si booléen_n est #t . C'est l'équivalent du « case of » de certains langages. La dernière expression, introduite par else, est évaluée si toutes les autres sont fausses ; elle est optionnelle.
Prédicats
[modifier | modifier le wikicode]Les principaux prédicats sont :
=: égalité numérique ;eq?ouequal?: égalité de deux expressions ;eqv?: équivalence de deux expressions ; la différence entre l'égalité et l'équivalence est que l'égalité concerne le contenu, l'équivalence concerne l'expression ; ainsi, deux listes de même contenu mais créées séparément ne sont pas équivalentes ;<,>: relations d'ordre strictes ;<=,>=: relations d'ordre larges ;null?: l'expression est-elle la liste vide ?list?: l'expression est-elle une liste (éventuellement vide, mais pas une liste pointée) ?pair?: l'expression est-elle une paire ? (Une liste non vide est une paire)number?: l'expression est-elle une constante de type nombre ?
Par ailleurs, on dispose des opérateurs logiques classiques or (ou logique), and (et logique), not (non logique).
Boucle
[modifier | modifier le wikicode]Scheme ne possède pas de structure de boucle. Le problème est traité par la récursivité (voir plus loin).
Il existe toutefois un opérateur map qui applique une fonction successivement à une liste d'arguments.
- Exemple
- pour calculer les racines carrées des nombres de 1 à 5 :
scheme> (map sqrt '(1 2 3 4 5)) ⇒ (1 1.4142135623730951 1.7320508075688772 2 2.23606797749979)
Exemples
[modifier | modifier le wikicode]- Opérations sur plusieurs nombres
scheme> (+ 1 2 3 4) ⇒ 10
- (soit « 1+2+3+4 » en notation infixée)
scheme> (- 1 2 3) ⇒ -4
- (soit « 1-2-3 » en notation infixée)
scheme> (/ 1 2 3) ⇒ 1/6
- (soit « 1/2/3 » en notation infixée)
- Opérations imbriquées
scheme> (+ 1 (* 2 2)) ⇒ 5
- (soit « 1+2×2 » en notation infixée)
scheme> (expt (cos (/ 3.1416 2)) 2) ⇒ 0.4999981633974483
- soit à peu près ½, puisque cos(π/2) = 1/√2
- Définir une liste d'entiers
- Il y a quatre manières équivalentes de définir la liste (1 2 3 4) :
'(1 2 3 4) / (quote (1 2 3 4)) (list 1 2 3 4) (cons 1 (cons 2 (cons 3 (cons 4 ()))))
- Fonction simple
- La fonction
doublemultiplie un nombre par deux :
scheme> (define (double x) (* 2 x))
- Pour l'utiliser :
scheme> (double 3) ⇒ 6
Paires et listes
[modifier | modifier le wikicode]Si l'on représente les paires comme des boîtes à deux cases, alors on a les équivalences suivantes entre listes et paires :
| Liste | Paire | ||||
|---|---|---|---|---|---|
(a)
|
| ||||
(a . b)
|
| ||||
(a b)
|
|
On voit que la liste (a b) est en fait une paire de paires.
Si on représente les paires comme les nœuds d'un arbre, on a la représentation suivante.
| Liste | Paire |
|---|---|
(a)
|
* / \ a () |
(a . b)
|
* / \ a b |
(a b)
|
* / \ a * / \ b () |
- Exemples
scheme>'(a . ()) ⇒(a)
scheme>'(a . (b . ())) ⇒(a b)
À l'origine, le Lisp a été écrit pour les IBM 704. Une paire était alors représentée par deux valeurs : une adresse et une partie décrémentale, d'où les acronymes :
car: content of address of register ;cdr: content of decrement of register.
Notez que car se prononce tel quel (à l'anglaise) et que cdr se prononce approximativement « cadeur » ou « coudeur » (/'kʌ dər/ ou /'ku dər/). Dans le jargon du MIT, on utilise le verbe to cdr down dans le sens « examiner les éléments d'une liste un par un » (cons a quant à lui donné le verbe to cons up).
Les opérateurs car et cdr peuvent être composés :
(caar ( … ))est l'équivalent de(car ( car … ));(cddr ( … ))est l'équivalent de(cdr ( cdr … ));(cadr ( … ))est l'équivalent de(car ( cdr … ));(cdar ( … ))est l'équivalent de(cdr ( car … ));- …
- Exemples
scheme> (caar '((1 2) 3)) ⇒ 1 scheme> (cddr '(1 2 3)) ⇒ (3) scheme> (cadr '(1 2 3)) ⇒ 2 scheme> (cdar '((1 2) 3)) ⇒ (2)
Importance de la grammaire
[modifier | modifier le wikicode]Le Lisp, dont est dérivé Scheme, a été conçu essentiellement en tant que formalisme, dans le sens : représentation formelle et systématique des données et instructions. À l'inverse de nombreux langages qui proposent de nombreuses instructions avec pour chaque une syntaxe adaptée à leur utilisation, Lisp et Scheme proposent une grammaire, une manière systématique de représenter les données et les instructions, sous forme d'expressions symboliques ou « S-expressions ».
Cela en a fait un outil de choix pour le travail sur l'intelligence artificielle, puisque l'on s'intéresse là à la possibilité d'apprentissage, au développement de nouvelles fonctionnalité plus qu'à un corpus préétabli d'instructions.
Si l'on résume la grammaire, on a :
- un vocabulaire de base composé de trois type de mots :
- les variables, notées dans le tableau ci-dessous
<var>; - les constantes, notées dans le tableau ci-dessous
<cst>; - les opérations primitives, notées dans le tableau ci-dessous
<prm>;
- les variables, notées dans le tableau ci-dessous
- deux types de phrases :
- les expressions, notées dans le tableau ci-dessous
<exp>; - les définitions globales, notées dans le tableau ci-dessous
<def>.
- les expressions, notées dans le tableau ci-dessous
Le tableau ci-dessous, inspiré de [1] indique des exemples de syntaxe ; les exemples sont séparés par un tube « | ».
| Vocabulaire | ||
|---|---|---|
<var> |
= | x | i | diametre_du_tube | …
|
<cst> |
= | -1 | 1 | 3/2 | 2.72 | …| |
<prm> |
= | + |* | cos | if | let | …
|
| Grammaire | ||
<def> |
= | (define (<var> <var> … <var>) <exp>)
|
<exp> |
= | <var>|
|
Voir aussi
[modifier | modifier le wikicode]- Dans Wikipédia
- Arborescence
- Intelligence artificielle
- S-expression
- (anglais) CAR and CDR
- (anglais) Cons
- Autre
