Sans calculette

publicité
Algorithmique-Programmation : IAP1 - 3 novembre 2008
Sans documents - durée : 1h30 Sans calculette
Les exercices sont indépendants. Ne vous bloquez donc pas sur une question.
Pour répondre à certaines questions, il se peut que vous ayez besoin de définir des fonctions auxiliaires. Dans
ce cas indiquez clairement ce que font ces fonctions auxiliaires en donnant par exemple leur interface.
Pour les fonctions explicitement demandées dans l’énoncé, n’écrivez leur interface que si celle-ci est explicitement demandée dans l’énoncé.
Exercice 1 (Typage, évaluation)
let rec foo l f = match l with
[] -> []
| e::r -> (e f)::(foo r f);;
Question 1
Quel est le type (le plus général) de la fonction foo ? Vous expliquerez en quelques phrases le plus
clairement possible comment vous avez obtenu le type précédent.
Question 2
Quel est le type de l’expression foo [succ;function x -> x*x] 2 ? La fonction succ est la fonction
successeur des entiers.
Quelle est la valeur de l’expression foo [succ;function x -> x*x] 2 ?
Question 3
Quel est le type de l’expression foo [function s -> "ab" ; function s -> s^s ] ?
Quelle est la valeur de l’expression foo [function s -> "ab" ; function s -> s^s] ?
Exercice 2 (Petite session à compléter)
Question 4
Compléter en donnant les réponses de Caml si on lit les phrases dans l’ordre 1, 2, 3 et 4.
1. #let rec until a f p = if p a then [a] else a::(until (f a) f p);;
2. #let qui n m
= if n<=m then until n (function y -> y+1) (function y -> y >= m) else [];;
3. #qui 2 8;;
4. #qui 2 0;;
Exercice 3 (Expressions arithmétiques)
Soit expr le type des expressions arithmétiques défini ci-dessous :
type expr = Const of int | Var of string | Plus of expr * expr;;
Question 5
Écrire une fonction egal qui teste l’égalité de deux expressions de type expr. Le constructeur Plus sera
considéré commutatif, ainsi l’expression (x + y) + 2 est égale à l’expression 2 + (y + x). Mais l’expression
(x + y) + 2 n’est pas égale à l’expression x + ( y + 2). On ne considèrera pas en effet la propriété
d’associativité.
On désire ajouter aux expressions précédentes les expressions de la forme let x = e1 in e2 où e1 et
e2 sont deux expressions.
Question 6
1
Modifier le type expr pour prendre en compte ce nouveau genre d’expression.
Question 7
Quelle est la valeur de type expr qui code l’expression let x=y+1 in x+2 ? On l’appellera ex1 dans la
suite.
On dit qu’une variable est libre si elle n’est pas introduite par un let. Par exemple, dans l’expression
let x=y+1 in x+2, la variable y est dite libre. Dans l’expression, let x=x+1 in x+2, la variable x dans
l’expression x+1 est libre. Mais la variable x dans la sous-expression x+2 n’est pas libre, elle est introduite
par le let.
Question 8
Écrire une fonction libres qui prend en paramètre une expression et retourne la liste des noms des
variables qui ont au moins une occurrence libre dans l’expression. Par exemple libres ex1 retourne la liste
["y"] alors que le résultat pour l’expression let x = x + y in x + 1 sera la liste ["x"; "y"].
Question 9
Écrire une fonction evalue qui prend en paramètre une expression et un environnement (une liste de
couples de la forme (nom de variable, valeur entière)) et retourne la valeur de l’expression. Si une variable libre
n’a pas de valeur alors la fonction échouera. Par exemple la valeur de l’expression ex1 dans l’environnement
[("y", 5)] est l’entier 8. On rappelle que le calcul de la valeur d’une expression let x = e1 in e2 se fait
en évaluant d’abord l’expression e1 (soit v sa valeur) puis en évaluant l’expression e2 en considérant que x
désigne la valeur v.
Exercice 4 (Graphes)
On désire représenter et manipuler un graphe orienté en Caml. Pour simplifier on suppose dans la suite
que les sommets sont représentés par des entiers mais ils pourraient être de n’importe quel type.
Partie 1
Dans cette partie un graphe orienté est représenté par la liste de ses arcs. Un arc de x vers y est représenté par
le couple (x, y). On dit dans ce cas que y est un successeur de x. Un graphe est donc de type (int ∗ int) list.
On désignera ce type par graphe dans la suite.
Soit gtest le graphe [(1, 2); (1, 4); (2, 1); (2, 3)].
Question 10
Écrire une fonction estsucc dont l’interface est donnée ci dessous :
(*interface estsucc
type : graphe * int * int -> bool
arguments : g x y
pre : true
post : retourne true si x est un successeur de y dans le graphe g, false sinon.
tests : estsucc (gtest,4,1) (* true*), estsucc (gtest,4,2) (* false*), estsucc (gtest,5,1) (* false*)
*)
Question 11
Écrire une fonction successeurs qui prend deux paramètres : un graphe g et un sommet s, et retourne
la liste des successeurs de s dans g. Elle retourne la liste vide si le sommet ne figure pas dans le graphe.
Question 12
Réécrire la fonction précédente en utilisant la fonctionnelle f old lef t ou f old right.
Question 13
Écrire une fonction qui retourne la liste des sommets d’un graphe (on suppose que le graphe ne contient
pas de sommets isolés, i.e non reliés à un autre). On veut obtenir le résultat sous la forme d’un liste
2
sans doublons et ordonnée dans l’ordre croissant des sommets. Une solution qui consisterait à chercher les
sommets puis à supprimer les doublons et trier (ou l’inverse) sera refusée. On pourra si besoin est définir une
ou plusieurs fonctions intermédiaires. Toute fonction intermédiaire doit être accompagnée de son interface.
Si cette dernière ne figure pas, la solution sera ignorée.
Partie 2
On adopte maintenant une autre représentation pour un graphe. Pour chaque sommet on dispose de la liste
non vide de ses successeurs. Ainsi le graphe gtest sera représenté par la valeur [(1, [2; 4]); (2, [1; 3])]. Un
sommet qui n’a pas de successeur ne figure pas en tant que premier composant d’un couple dans la liste.
Question 14
Réécrire la fonction précédente estsucc en supposant que le graphe est maintenant de type (int ∗ (int list)) list.
Pour écrire cette fonction vous utiliserez (entre autres) la fonction assoc dont l’interface est rappelée en fin
de sujet.
Question 15
Réécrire la fonction précédente successeurs en supposant que le graphe est maintenant de type (int ∗ (int list)) list.
Partie 3
Un chemin de x1 à xn est une liste de sommets [x1 ; x2 ; ...xn ] telle que (x1, x2) soit un arc du graphe, (x2, x3)
un autre arc, ..., (xn−1 , xn ) soit aussi un arc du graphe.
Question 16
Écrire une fonction estchemin qui prend en paramètre un graphe g et un chemin ch et retourne true
si ch est un chemin du graphe g et f alse sinon. Par exemple, estchemin gtest [1; 2; 1] retourne true,
estchemin gtest [1; 2; 3] retourne true, estchemin gtest [1; 2; 4] retourne f alse et estchemin gtest [1; 2; 5]
retourne f alse. Vous utiliserez les fonctions estsucc ou successeurs précédentes pour écrire votre fonction,
vous ne devez en aucun cas supposer que l’on a choisi l’une ou l’autre des 2 représentations proposées pour
le graphe.
Il s’agit maintenant de trouver un chemin de x à y dans un graphe g. Il peut y avoir plusieurs chemins
reliant un sommet à un autre. On veut écrire une fonction chemin qui prend en paramètre g, x et y et
retourne un chemin (sous la forme d’une liste de sommets comme précédemment) reliant x à y dans le
graphe g s’il en existe un et échoue sinon. Dans ce dernier cas, la fonction lèvera l’exception Impossible.
Par exemple, on obtiendra :
#
#
#
-
chemin gtest
: int list =
chemin gtest
: int list =
chemin gtest
: int list =
1 1;;
[1; 2; 1]
1 3;;
[1; 2; 3]
2 4;;
[2; 1; 4]
Question 17
Déclarer l’exception Impossible.
Question 18
Écrire la fonction chemin en vous appuyant sur les remarques suivantes :
Si y est un successeur de x, alors le chemin reliant x à y est tout trouvé. Sinon, si z est un successeur possible
pour x, un chemin de x à y est alors un chemin de x à z (un arc) suivi d’un chemin de z à y. Ici aussi vous
ne ferez aucune supposition sur le type de représentation choisie pour le graphe. Si besoin est, utilisez les
fonctions estsucc et successeurs.
Rappel : fonctionnelles classiques sur les listes :
3
let rec map f li = match li with
[] -> []
| x::l -> (f x)::(map f l);;
let rec filter p li = match li with
[] -> []
| x::l -> if (p x) then x::(filter p l) else (filter p l);;
let rec fold_right f l e = match l with
[] -> e
| a::r -> f a (fold_right f r e);;
let rec fold_left f e l = match l with
[] -> e
| a::r -> fold_left f (f e a) r;;
Interface de la fonction assoc :
(*
interface assoc
type : ’a -> ’a * ’b list -> ’b
arguments x l
precondition : il existe un couple de la forme (x,y) dans l
postcondition : retourne y
raises : Not_Found si il n’y aucun couple de la forme (x,..) dans l
*)
4
Téléchargement