Chapitre 9 Annexe : résumés
| 9.1 Chapitre 0
|
♦ Conseils de lecture :
-
lisez tous les paragraphes, et faites tous les exercices, sans exception;
- si vous bloquez sur un exercice, cherchez au moins 10 minutes avant de regarder la correction, mais ne passez jamais plus de 20 minutes sur un petit exercice (regardez votre montre);
- lorsque vous avez fini un exercice, retenez bien la solution, elle servira presque sûrement dans la suite;
- essayez de présenter vos programmes de la même manière que dans le cours;
- évitez de faire du copier-coller de code, car c'est en écrivant du code que l'on apprend.
|
|
| 9.2 Chapitre 1
|
♦ Pour effectuer plusieurs instructions, il suffit de les écrire à la suite les unes des autres.
♦ On écrira une seule instruction par ligne.
♦ La règle d'exécution d'un "let nom = ... in" est la suivante :
-
calcule la valeur de l'expression entre le signe = et le in,
- remplace le nom par cette valeur dans les instructions concernées,
- passe alors à l'exécution de la suite.
♦ Un nom de valeur doit être formé de lettres de bases (de a à z ou de A à Z), de chiffres, et d'underscores (le symbole _), et doit en outre commencer par une lettre minuscule. Il ne faut pas mettre d'espaces, ni de lettres accentuées ou tout autre caractère spécial.
♦ Un read_int() bloque l'exécution du programme jusqu'à ce que
l'utilisateur ait tapé un nombre entier, et ait appuyé sur la touche entrée du clavier.
A ce moment le mot read_int() est remplacé par la valeur donnée.
♦ Pour demander des données à l'utilisateur, on en posera toujours la valeur avec un let.
♦ read_line() permet de demander à l'utilisateur une ligne de texte.
♦ Fonctionnement de la structure if, then, else :
-
On teste la condition qui se trouve après le if.
- Si ce test est vérifié, on exécute juste le bloc du then.
- Dans le cas contraire, on exécute juste le bloc du else.
- Dans les deux cas, on continue ensuite l'exécution après le point-virgule finale.
♦ Une association effectuée dans un des blocs d'une structure en if a une portée
limitée à ce bloc.
♦
se simplifie simplement en "instruction".
♦ Dans une structure if, lorsque les blocs du then et du else sont réduits à
une instruction chacun, on adopte la présentation suivante :
if (...condition...)
then (...instruction du then...)
else (...instruction du else...);
|
♦ Un bloc vide begin end peut s'écrire aussi comme un couple de parenthèses : ().
♦ Dans une structure if, on peut se passer du "else ()".
♦ Lorsque le bloc du else contient lui-même une structure if,
on peut enlever les délimiteurs du bloc begin et end.
Dans ce cas, il faut aussi enlever le point-virgule terminant le bloc imbriqué.
♦ Voici une structure avec des else if :
if (...1ere condition...) then
(...bloc du 1er then...)
else if (...2ème condition...) then
(...bloc du 2eme then...)
else if (...3ème condition...) then
(...bloc du 3eme then...)
...
...
else
( ...bloc du else...)
;
|
♦ Fonctionnement de la boucle for, utilisée pour répéter un bloc :
-
La première ligne permet de préciser le nombre de fois qu'il faut répéter la boucle.
- Les bornes do et done délimitent le bloc qu'on va répéter.
- Le corps de la boucle for sera copié autant de fois qu'indiqué à la première ligne.
- L'ensemble de la structure, formant une grosse instruction, doit être terminé par un point-virgule.
♦ Les déclarations réalisées à l'intérieur du corps de la boucle
ont une portée limitée à ce corps.
♦ Fonctionnement de la boucle for utilisé pour itérer un bloc avec un compteur :
-
Évaluer la valeur initiale et la valeur finale du compteur, ce sont les bornes.
- Prendre dans l'ordre croissant tous les entiers compris entre ces bornes, incluses.
- Pour chaque entier, copier le corps du for, et y déclarer le compteur égal à cet entier.
♦ Lorsque la valeur initiale du compteur est égale à la valeur finale,
la boucle n'est exécutée qu'une seule fois pour cette valeur. Lorsque la valeur initiale
est supérieure strictement à la valeur finale, la boucle n'est exécutée aucune fois.
♦ Remplacer to par downto dans une boucle for
pour avoir des valeurs du compteur décroissantes.
|
|
| 9.3 Chapitre 2
|
♦ Il est impossible de mélanger des int et des float sans soins particuliers
♦ Lorsqu'on effectue une division par zéro en calculant sur des réels, un code spécial est utilisé pour désigner le résultat. Sous Windows :
-
1.#INF et -1.#INF respectivement pour plus et moins l'infini.
- 1.#IND et -1.#IND pour des valeurs indéterminées.
Sous linux :
-
inf. et -inf. respectivement pour plus et moins l'infini.
- nan. et -nan. pour des valeurs indéterminées.
♦ Pour calculer la valeur absolue d'un réel x, on fait abs_float x.
♦ Pour prendre la racine carrée d'un nombre réel x, on fait sqrt x.
♦ La fonction max donne le plus grand de deux nombres réels.
♦ L'opérateur / représente la division entière.
♦ L'opérateur mod calcule le reste de la division entière.
♦ La fonction float_of_int convertit un entier en le réel correspondant.
♦ Un int est une valeur comprise entre -1073741824 et 1073741823.
♦ Lorsqu'on travaille avec des int, il faut faire attention à ne pas dépasser les limites, car aucun message d'erreur ne signale les dépassements.
♦ Pour créer une boite, il faut donner un contenu initial. A tout instant, la boite contiendra un et un seul objet du même type que ce contenu initial.
♦ Résumé des manipulations de références :
-
let nom = ref contenu in pour construire une nouvelle référence.
- !nom pour accéder au contenu de la référence.
- nom := nouveau_contenu pour affecter un nouveau contenu à la référence.
|
|
| 9.4 Chapitre 3
|
♦ Pour nommer une fonction, on choisit toujours un nom décrivant précisément
l'action réalisée par le corps de cette fonction.
♦ Pour définir une fonction, on écrit :
let (...nom de la fonction...) (...noms des arguments...) =
(...instructions du corps de la fonction...)
in
|
♦ Pour appeler une fonction qui ne retourne rien, on écrit :
(...nom de la fonction...) (...valeurs des arguments...) ;
|
♦ Lorsqu'il y a plusieurs paramètres à une fonction, on les place simplement séparés par des espaces.
♦ Lorsqu'il n'y a aucun paramètre à une fonction, on place un couple de parenthèses.
♦ Le schéma d'une fonction qui retourne une valeur est le suivant :
let (...nom de la fonction...) (...noms des paramètres...) =
(...actions réalisées par la fonction...)
(...valeur de retour...) in
|
♦ La valeur de retour d'une fonction peut être le résultat d'une structure if :
let (...nom de la fonction...) (...noms des paramètre...) =
(...actions de la fonction...)
if (...condition...)
then (...valeur de retour 1...)
else (...valeur de retour 2...)
in
|
Cette structure fonctionne aussi avec les else if.
♦ Le schéma général d'une fonction est le suivant :
let (...nom de la fonction...) (...noms des paramètres...) =
(...actions réalisées par la fonction...)
(...valeur de retour...) in
|
-
si la fonction n'a pas d'argument, on place juste un couple de parenthèses;
- il peut n'y avoir aucune action réalisées par la fonction;
- si la fonction ne retourne rien, il n'y a pas de valeur de retour avant le in.
- la valeur de retour peut être le résultat d'un test.
|
|
| 9.5 Chapitre 4
|
♦ Résumé des manipulations de tableaux :
-
Création d'un tableau, première version : [| elem1; elem2; ... elemN |]
- Création d'un tableau, seconde version : Array.make taille motif
- Accès à l'élément d'indice i : tab.(i)
- Modification de l'élément d'indice i : tab.(i) <- nouvel_valeur
- Longueur d'un tableau : Array.length tab
- Accès à un indice invalide : exception Invalid_argument("Array.get")
- Modification à un indice invalide : exception Invalid_argument("Array.set")
♦ La fonction Array.copy prend en paramètre un tableau et retourne un autre tableau, copie conforme du premier.
♦ Un caractère est une valeur de type char qu'on construit en plaçant le caractère entre des guillemets simples.
♦ Résumé des manipulations de chaînes :
-
Création d'une chaîne, première version : "mon texte"
- Création d'une chaîne, seconde version : String.make taille un_caractère
- Longueur d'une chaîne : String.length str
- Accès à un caractère : str.[i]
- Modification d'un caractère : str.[i] <- nouveau_caractère
- Copie d'une chaîne : String.copy str.
- Concaténation de deux chaînes : str1 ^ str2.
♦ On peut convertir un nombre entier en la chaîne qui le représente à l'aide de la fonction string_of_int.
♦ string_of_float permet de convertir un nombre flottant en la chaîne qui le représente.
|
|
| 9.6 Chapitre 5
|
♦ Une valeur booléenne (bool) vaut true ou false, et peut se construire avec des tests comparatifs.
♦ La condition d'un if est toujours une expression de type bool.
♦ Pour afficher des booléens, on définit généralement la fonction print_bool au préalable :
let print_bool b =
print_string (string_of_bool b);
in
|
♦ Résumé des opérateurs de calcul sur les expressions booléennes :
-
(expr1 && expr2) est vraie uniquement lorsque les deux expressions sont vraies.
- (expr1 || expr2) est vraie dès qu'une des deux expressions est vraie.
- (not expr1) est vraie lorsque l'expression est fausse, et fausse lorsque l'expression est vraie.
♦ Random.int k donne aléatoirement un entier compris entre 0 et k-1.
♦ L'instruction Random.self_init() doit être exécutée une fois pour toutes avant de pouvoir appeler le générateur de nombres aléatoires.
♦ La fonction Random.float x retourne un nombre aléatoire de type float compris
entre zéro (inclus) et x (exclus).
♦ Random.bool() a une chance sur deux de renvoyer true, et une chance sur deux de renvoyer false
|
|
| 9.7 Chapitre 6
|
♦ Voici le schéma de la boucle while :
while (...condition...) do
(...corps de la boucle while...)
done;
|
♦ Une fonction récursive est une fonction qui s'appelle elle-même.
♦ Pour définir une fonction récursive, on place le mot clé rec entre le let et le nom de la fonction.
♦ Un trop grand nombre d'appels récursifs imbriqués provoque un débordement de pile (stack overflow).
♦ Un stack overflow a souvent pour cause la récursivité infinie.
|
|
| 9.8 Chapitre 7
|
♦ Par définition, une expression qui réalise une action est de type unit.
♦ Une expression "expr1; expr2", où exrp1 est une expression de type unit, est de la valeur du type de l'expression expr2.
♦ Pour évaluer l'expression expr1; expr2 où exrp1 est une expression de type unit, on commence par faire l'action de expr1, puis on calcul la valeur de expr2.
♦ On peut forcer un certain groupement d'expressions avec des parenthèses ouvrante puis fermante, ou bien avec les bornes begin et end.
♦ L'expression let name = expr1 in expr2 vaut expr2 dans laquelle name est un nom qui peut être utilisé dans expr2, et qui représente la valeur de expr1 qu'on calcul une fois pour toutes.
♦ L'expression if expr1 then expr2 else expr3 où expr1 est une expression de type bool, et où les expressions expr2 et expr3 sont forcément de même type, constitue une structure décisionnelle. Lorsque la condition expr1 vaut true, la structure est équivalente à expr2, et dans le cas contraire lorsque expr1 vaut false, la structure est équivalente à expr3.
♦ L'expression if expr1 then expr2 est équivalente à if expr1 then expr2 else (). Par conséquent, expr1 doit être de type bool et expr2 doit être de type unit.
♦ L'expression expr1 && expr2 où les deux expr1 et expr2 sont de type bool est équivalente à if expr1 then expr2 else false.
♦ L'expression expr1 || expr2 où les deux expr1 et expr2 sont de type bool est équivalente à if expr1 then true else expr2.
♦ La structure :
for compteur = expr1 to expr2 do
expr3
done
|
où
-
compteur est le nom du compteur,
- expr1 et expr2 sont des entiers, valeurs initiale et finale.
- expr3 est une expression de type unit où l'on peut utiliser le nom du compteur, le corps de la boucle,
forme une expression de type unit, qui se comporte comme la répétition de expr3 pour toutes les valeurs de compteur comprises entre expr1 et expr2 inclus. S'il n'existe pas de telle valeur pour le compteur, alors la boucle ne fait rien et est équivalente à ().
♦ La structure :
while expr1 do
expr2
done
|
où expr1 (la condition de la boucle) est de type bool et expr2 (le corps de la boucle) de type unit est une expression de type unit, qui se comporte comme la répétition de expr2 tant que l'expression expr1 est évaluée à vrai.
♦ La définition d'une fonction :
let arg_de_la_fonction arg_1 arg_2 ... arg_N =
expr1 in
|
où arg_de_la_fonction et tous les arg_i sont des noms, forme une expression de type :
type(arg_1) -> type(arg_2) -> ... -> type(arg_N) -> type(expr_1)
|
les types des arguments étant déduits de l'utilisation qui en est faîte dans expr1.
♦ L'expression :
nom_de_fonction expr_1 expr_2 ... expr_N
|
lorsque nom_de_fonction est associé à une fonction de type
type_arg_1 -> type_arg_2 -> ... -> type_arg_N -> type_retour
|
est une expression de type type_retour, à condition que chaque expr_i soit de type type_arg_i.
♦ Les arguments d'une fonction sont tous évalués avant l'exécution de la fonction. L'ordre d'évaluation des arguments n'est pas spécifié
♦ Pour préciser un ordre de calcul des arguments lors de l'application d'une fonction, on les définit auparavant avec un let dans l'ordre souhaité
|
|
| 9.9 Chapitre 8
|
♦ Il est recommandé d'étudier le clavier pendant une ou deux minutes avant de commencer à programmer, plutôt que de se reporter à l'annexe clavier trop souvent
|
|
|
|