<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>http://os-vps418.infomaniak.ch:1250/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Caroline</id>
	<title>Wiki du LAMA (UMR 5127) - Contributions [fr]</title>
	<link rel="self" type="application/atom+xml" href="http://os-vps418.infomaniak.ch:1250/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Caroline"/>
	<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php/Sp%C3%A9cial:Contributions/Caroline"/>
	<updated>2026-05-21T09:43:52Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.39.4</generator>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO401_corr_TD_TP&amp;diff=3895</id>
		<title>INFO401 corr TD TP</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO401_corr_TD_TP&amp;diff=3895"/>
		<updated>2009-03-04T10:22:53Z</updated>

		<summary type="html">&lt;p&gt;Caroline : /* Le TP1 - début */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
Pour afficher correctement dans le wiki, allez voir un peu comment on fait. Vous pouvez regarder par exemple sur le [[INFO401 | wiki du cours]] ou directement sur des articles de [http://fr.wikipedia.org/wiki/Accueil Wikipedia]. La documentation de mediawiki se trouve [http://meta.wikimedia.org/wiki/Aide:Éditeur ici].&lt;br /&gt;
&lt;br /&gt;
Un truc important : pour rentrer du code Caml, il faut mettre les balises &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;...&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt; autour de votre code. Allez par exemple voir le début de la section sur [[#Le TD1 et le TP0 | le TD1 et TP0]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aller discuter des corrections dans les sujets de discussions associes...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Le TD1 et le TP0==&lt;br /&gt;
&lt;br /&gt;
Pour vous montrer un exemple de ce que j&#039;attends, voila la correction de la fonction factorielle. (C&#039;était facile...) J&#039;ai volontairement mis beaucoup de commentaires...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;La fonction factorielle (TD1, exercice 2, question 2)&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le but est de calculer la fonction &amp;lt;math&amp;gt;!n = 1\times2\times \cdots \times n&amp;lt;/math&amp;gt; par récurrence. La version typée est verbeuse de la fonction correspondante en Caml donne :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* fonction factorielle : c&#039;est la factorielle habituelle des mathématiciens... *)&lt;br /&gt;
let rec fact (n:int) : int =&lt;br /&gt;
  if (n&amp;gt;1)&lt;br /&gt;
  then  n * (fact (n-1))&lt;br /&gt;
  else 1      (* rq : pour que le programme ne boucle pas sur les valeurs négatives, on renvoie 1 dés que n&amp;lt;1 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme la fonction est récursive, il ne faut pas oublier le &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; au début de la définition.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On aurait pu faire une autre version, qui fonctionne différemment sur les nombres négatifs :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fact&#039; = function&lt;br /&gt;
   n when (n&amp;gt;0) -&amp;gt; n * fact&#039; (n-1)&lt;br /&gt;
 | n when (n&amp;lt;0) -&amp;gt; n * fact&#039; (n+1)&lt;br /&gt;
 | _ -&amp;gt; 1  (* si n n&#039;est ni plus petit que 0 ni plus grand que 0, n est égal à 0, et on renvoie donc 1 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J&#039;ai volontairement mis une version qui contient plusieurs choses que nous n&#039;avons pas encore vues en cours :&lt;br /&gt;
* utilisation de &amp;quot;&amp;lt;tt&amp;gt;function&amp;lt;/tt&amp;gt;&amp;quot; plutôt que &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;,&lt;br /&gt;
* le mot clé &amp;quot;&amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Vous devriez pouvoir comprendre ce que fait la fonction. Sinon, voici une version que vous auriez pu écrire :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fact_bis = fun n -&amp;gt;&lt;br /&gt;
  if (n=0)&lt;br /&gt;
  then 1&lt;br /&gt;
  else begin&lt;br /&gt;
    if (n&amp;gt;0)&lt;br /&gt;
    then n*fact_bis (n-1)&lt;br /&gt;
    else n*fact_bis (n+1)   (* dans ce cas, n est forcement négatif *)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Les fonctions sommes &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il s&#039;agit ici d&#039;écrire la fonction qui va additionner les carrés des entiers de 1 jusqu&#039;à un nombre donné.&lt;br /&gt;
&lt;br /&gt;
Cela donne :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec somme_carre b =&lt;br /&gt;
if (b=0) then 0&lt;br /&gt;
else (b*b) + somme_carre (b-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ensuite on nous demande de calculer la somme des cubes des entiers de 1 jusqu&#039;à un nombre donné. On pourrait faire le même programme en remplaçant b*b par b*b*b, mais on va définir une fonction puissance (car elle n&#039;existe pas d&#039;origine sous Caml), qui nous servira aussi pour la suite... :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec puissance x a =&lt;br /&gt;
if (a = 0) then 1&lt;br /&gt;
else x * puissance x (a-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On doit maintenant calculer la somme des &amp;lt;math&amp;gt;i^i&amp;lt;/math&amp;gt;, i variant de 1 à un nombre donné :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec somme_puissance b =&lt;br /&gt;
if (b=0) then 0&lt;br /&gt;
else (puissance b b) + somme_puissance (b-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On peut définir une unique fonction qui permettrait de faire toutes ces sommes, celle-ci aura pour argument une fonction quelconque :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec somme_fonction n f = (* f étant une fonction *)&lt;br /&gt;
if (n=0) then f 0&lt;br /&gt;
else f n + somme_fonction (n-1) f;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
cette fonction est de type &amp;quot;&amp;lt;tt&amp;gt;int -&amp;gt; fun -&amp;gt; int&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Nombres pairs et impairs (TP0 Partie 2 Question 2) &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il faut écrire les fonctions récursives pairs et impairs, qui renvoient vrai si le nombre est pair (respectivement impair) et faux si le nombre est impair (respectivement pair);&lt;br /&gt;
Ici nous devons déclarer simultanément les deux fonctions, car chacune fait appel à l&#039;autre lors de son exécution.&lt;br /&gt;
&lt;br /&gt;
Cela donne :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec pair n =&lt;br /&gt;
  if (n=0) then true&lt;br /&gt;
  else impair (n-1)&lt;br /&gt;
and impair n =&lt;br /&gt;
  if (n=0) then false&lt;br /&gt;
  else  pair (n-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Suite de Fibonacci &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La suite de fibonacci est tel que u&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;=0 u&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;=1 et u&amp;lt;sub&amp;gt;n+2&amp;lt;/sub&amp;gt;=u&amp;lt;sub&amp;gt;n+1&amp;lt;/sub&amp;gt;+u&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fib n =&lt;br /&gt;
if (n=0) then 0&lt;br /&gt;
else if (n=1) then 1&lt;br /&gt;
else fib (n-1) + fib (n-2);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La plus grande valeur que l&#039;on peut obtenir sans que cela soit trop long est 24157817, ce qui correspond à fib 37.&lt;br /&gt;
Nous trouvons qu&#039;il faut déjà 88 additions pour calculer fib 10.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Rq :&#039;&#039;&#039; fib de 37 prend effectivement beaucoup de temps. Il faut 39088168 additions avant d&#039;en arriver à bout. Il est possible de faire une version de Fibonacci qui va très vite et qui calcule &amp;lt;tt&amp;gt;fib 37&amp;lt;/tt&amp;gt; en seulement 36 additions...&lt;br /&gt;
: Comment ?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Dragon ! &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;i&amp;gt; Le dragon est une créature mythique, présente dans de nombreuses cultures.&lt;br /&gt;
  On peut déterminer deux grands types de dragons : le dragon occidental et le dragon oriental&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction dragon a pour but de dessiner un dragon, pour cela on utilise une fonction récursive qui admet pour argument le nombre n d&#039;itération de la fonction, et les coordonnées de 2 points. A chaque itération, la fonction calcule pour chaque segment, un nouveau point et le relie ensuite aux deux autres.&lt;br /&gt;
&lt;br /&gt;
On obtient en tout 2&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; segments entremêlés, qui forment un dragon.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s go !&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec dragon (n:int) (a:int) (b:int) (c:int) (d:int) : unit =&lt;br /&gt;
if (n = 0) then (moveto a b ; lineto c d)&lt;br /&gt;
               else begin&lt;br /&gt;
                      let x = (a+c+d-b)/2 in&lt;br /&gt;
                      let y = (b+d+a-c)/2 in&lt;br /&gt;
                      dragon (n-1) a b x y ;&lt;br /&gt;
                      dragon (n-1) c d x y&lt;br /&gt;
                    end ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Rq : &#039;&#039;&#039; votre version du dragon est bien, mais pas très précises. (Je chipote un peu...)  Pour les paramètres (&amp;lt;tt&amp;gt;dragon 11 100 100 400 400&amp;lt;/tt&amp;gt;), de nombreux carrés ne sont pas bien tracés.&lt;br /&gt;
:Comment expliquez-vous cela, et comment pouvez-vous le corriger ?&lt;br /&gt;
&lt;br /&gt;
::Pour améliorer la précision je suggère de passer les coordonnées en type Float. --[[Utilisateur:Nicolas|Nicolas]] 31 janvier 2009 à 11:42 (CET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Le TD2==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Exercice 1 : Tuples&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Question 4 :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
On définit la fonction curry par:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let curry (f: &#039;a * &#039;b -&amp;gt; &#039;c) : &#039;a -&amp;gt; &#039;b -&amp;gt; &#039;c&lt;br /&gt;
     = fun x y -&amp;gt; f(x,y);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ou encore en simplifiant:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let curry f x y = f(x,y);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On définit ensuite la fonction uncurry par:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry (f: &#039;a -&amp;gt; &#039;b -&amp;gt; &#039;c) : &#039;a * &#039;b -&amp;gt; &#039;c&lt;br /&gt;
     = fun x -&amp;gt; f (fst x) (snd x);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ou encore de trois autres manières plus simplifiées:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry f = fun x -&amp;gt; f (fst x) (snd x);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry f = fun x -&amp;gt; match x with (a,b) -&amp;gt; f a b;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry f = function (a,b) -&amp;gt; f a b;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Avantage de la première forme (à plusieurs arguments): Elle permet une application partielle: on peut appliquer cette fonction à une seule partie des arguments.&lt;br /&gt;
&lt;br /&gt;
Inconvénients de la seconde forme (à un argument): &lt;br /&gt;
*il faut faire appel à fst, snd;&lt;br /&gt;
*Caml doit séparer les paires: c&#039;est une perte de temps&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Question 5 :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
D&#039;après la fonction récursive Fibonacci définit par &amp;lt;br /&amp;gt;&lt;br /&gt;
f(0)=0 &amp;lt;br /&amp;gt;&lt;br /&gt;
f(1)=1 &amp;lt;br /&amp;gt;&lt;br /&gt;
f(n+2)=f(n+1)+f(n), &amp;lt;br /&amp;gt;&lt;br /&gt;
comment compter le nombre d&#039;appels récursifs en Caml? &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec fib n =&lt;br /&gt;
     if (n&amp;lt;2) then (n,0)&lt;br /&gt;
     else let t = fib (n-1) in&lt;br /&gt;
          let s = fib (n-2) in &lt;br /&gt;
     (fst t + fst s , snd t + snd s + 1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&#039;&#039;exemple : &#039;&#039;fib 10 = (55, 88) pour exécuter la fonction Fibonacci(10), il y a 88 appels récursifs nécessaires...&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Exercice 2 : Listes&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Question 5 :&#039;&#039;&#039;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
suite à l&#039;étude des fonctions &lt;br /&gt;
*longueur&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec longueur l=&lt;br /&gt;
     match l with&lt;br /&gt;
     [] -&amp;gt;0&lt;br /&gt;
     | _ :: l -&amp;gt; 1+longueur l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*applique&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec app f p =&lt;br /&gt;
     match p with &lt;br /&gt;
     [] -&amp;gt; []&lt;br /&gt;
     | a :: p -&amp;gt; f(a) :: app f p&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*concatene&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec cat l1 l2 =&lt;br /&gt;
     match l1 with&lt;br /&gt;
     [] -&amp;gt; l2&lt;br /&gt;
     | a :: l -&amp;gt; a :: (cat l l2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*renverse,&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec renverse l =&lt;br /&gt;
     match l with&lt;br /&gt;
     [] -&amp;gt; []&lt;br /&gt;
     | a :: l -&amp;gt; (renverse l)@[a]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
on remarque des similitudes. Ces fonctions ont le même schéma de base ( celui de la fonction reduit) &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec reduit l o f =&lt;br /&gt;
     match l with&lt;br /&gt;
     [] -&amp;gt; o&lt;br /&gt;
     | a :: l -&amp;gt; f a (reduit l o f)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&#039;&#039;NB :&#039;&#039; val reduit : &#039;a list -&amp;gt; &#039;b -&amp;gt; (&#039;a -&amp;gt; &#039;b -&amp;gt; &#039;b) -&amp;gt; &#039;b = &amp;lt;fun&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Question 6 :&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Reprogrammons les fonctions précédentes à partir de la fonction reduit ! &amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let longueur l =&lt;br /&gt;
     let f _ r = 1 + r in &lt;br /&gt;
     reduit l o f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let app g l =&lt;br /&gt;
     let f  &lt;br /&gt;
     reduit l [] f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let cat l1 l2 =&lt;br /&gt;
     let f a r = a :: r in  &lt;br /&gt;
     reduit l1 l2 f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let renverse l =&lt;br /&gt;
     let f r a = [r]@[a]  &lt;br /&gt;
     reduit l [] f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Le TP1 - début==&lt;br /&gt;
&lt;br /&gt;
Le sujet [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/0809/info401/tp1.pdf programmes récursifs, listes], au format pdf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Partie 1 : Quelques compléments sur les programmes récursifs&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, on travaille sur la fonction Fibonacci&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 1&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On commence par l&#039;utiliser sous la forme :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fib n =&lt;br /&gt;
if n&amp;lt;2&lt;br /&gt;
   then n&lt;br /&gt;
   else fib (n-1) + fib (n-2)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour comprendre ce qu&#039;il se passe, on trace la fonction à l&#039;aide de &amp;quot;#trace&amp;quot; pour fib 5&lt;br /&gt;
&lt;br /&gt;
fib &amp;lt;-- n veut dire que l&#039;on donne la valeur n à la fonction fib&lt;br /&gt;
&lt;br /&gt;
alors que fib --&amp;gt; n veut dire que fib renvoie n&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# fib 5 ;;&lt;br /&gt;
fib &amp;lt;-- 5&lt;br /&gt;
fib &amp;lt;-- 3&lt;br /&gt;
fib &amp;lt;-- 1&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib &amp;lt;-- 2&lt;br /&gt;
fib &amp;lt;-- 0&lt;br /&gt;
fib --&amp;gt; 0&lt;br /&gt;
...&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib &amp;lt;-- 2&lt;br /&gt;
fib &amp;lt;-- 0&lt;br /&gt;
fib --&amp;gt; 0&lt;br /&gt;
fib &amp;lt;-- 1&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib --&amp;gt; 2&lt;br /&gt;
fib --&amp;gt; 3&lt;br /&gt;
fib --&amp;gt; 5&lt;br /&gt;
- : int = 5&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On peut remarquer que la fonction calcule plusieurs fois le même fib n.&lt;br /&gt;
Une optimisation consisterait à garder certaines valeurs en mémoire.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 2&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On écrit fib2 de type &amp;quot;int -&amp;gt; int*int&amp;quot; qui renvoie le valeur de fib n (fst fib2 n) et fib n-1 (snd (fib2 n)) :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fib2 n = &lt;br /&gt;
if n&amp;lt;2 &lt;br /&gt;
   then (n,n-1)&lt;br /&gt;
   else let t = fib2 (n-1) in&lt;br /&gt;
      (fst(t)+snd(t),fst(t));;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 3&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour comparer les fonctions fib et fib2, on les trace pour n=7 :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# fib 7 ;;&lt;br /&gt;
fib &amp;lt;-- 7&lt;br /&gt;
fib &amp;lt;-- 5&lt;br /&gt;
fib &amp;lt;-- 3&lt;br /&gt;
fib &amp;lt;-- 1&lt;br /&gt;
...&lt;br /&gt;
fib --&amp;gt; 3&lt;br /&gt;
fib --&amp;gt; 5&lt;br /&gt;
fib --&amp;gt; 8&lt;br /&gt;
fib --&amp;gt; 13&lt;br /&gt;
- : int = 13&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# fib2 7 ;;&lt;br /&gt;
fib2 &amp;lt;-- 7&lt;br /&gt;
fib2 &amp;lt;-- 6&lt;br /&gt;
fib2 &amp;lt;-- 5&lt;br /&gt;
fib2 &amp;lt;-- 4&lt;br /&gt;
fib2 &amp;lt;-- 3&lt;br /&gt;
fib2 &amp;lt;-- 2&lt;br /&gt;
fib2 &amp;lt;-- 1&lt;br /&gt;
fib2 --&amp;gt; (1, 0)&lt;br /&gt;
fib2 --&amp;gt; (1, 1)&lt;br /&gt;
fib2 --&amp;gt; (2, 1)&lt;br /&gt;
fib2 --&amp;gt; (3, 2)&lt;br /&gt;
fib2 --&amp;gt; (5, 3)&lt;br /&gt;
fib2 --&amp;gt; (8, 5)&lt;br /&gt;
fib2 --&amp;gt; (13, 8)&lt;br /&gt;
- : int * int = (13, 8)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
On remarque que fib2 fait 14 calculs alors que fib en 81 pour n=7.&lt;br /&gt;
Afin de retourner uniquement la valeur de fib n on définit une nouvelle fonction, beaucoup plus rapide que fib, &lt;br /&gt;
en prenant le premier élèment de la paire constituant fib2 n.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 4 ( Bonus )&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On veut créer fib3 de type int-&amp;gt;int-&amp;gt;int-&amp;gt;int tel que :&lt;br /&gt;
&lt;br /&gt;
- son premier argument est l&#039;entier n pour fibonacci de n&lt;br /&gt;
&lt;br /&gt;
- les 2 autres arguments sont des accumulateurs qui permettent de conserver des valeurs successives ( pour i-1 et i )&lt;br /&gt;
&lt;br /&gt;
 --- à venir ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Partie 2 : Manipulation des listes&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 1&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voici quelque fonctions d&#039;abord en définition directe, puis en utiliser la fonction List.fold right&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec longueur l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
|a::l&#039;-&amp;gt;1 + (longueur l&#039;)&lt;br /&gt;
&lt;br /&gt;
	let rec applique f l = match l with&lt;br /&gt;
	[]-&amp;gt;[]&lt;br /&gt;
	|a::l -&amp;gt; ( f a )::( applique f l )&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec applique f l = match l with&lt;br /&gt;
[]-&amp;gt;[]&lt;br /&gt;
|a::l -&amp;gt; ( f a )::( applique f l )&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec concatene l l&#039; = match l with&lt;br /&gt;
[]-&amp;gt;l&#039;&lt;br /&gt;
|a::l-&amp;gt;a::(concatene l l&#039;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let longueur_bis l = let f a r = 1 + r in List.fold_right l o f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let applique_bis f l = let f&#039; a r = ( f a )::r in List.fold_right l [] f&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let concatene_bis l1 l2 = let f a r = a::r in List.fold_right l1 l2 f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 2&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voici la fonction reverse telle qu&#039;on l&#039;a écrite dans le TD&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec reverse l = &lt;br /&gt;
  match l with&lt;br /&gt;
  []-&amp;gt;[]&lt;br /&gt;
  |a::l -&amp;gt; (reverse l)@[a] ;; &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour la comparer avec List.rev, on va regarder le temps d&#039;exécution sur une très grande liste.&lt;br /&gt;
&lt;br /&gt;
Pour cela, on créé une fonction qui fabrique une liste de n valeurs :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec liste_ordonnée l n  = &lt;br /&gt;
  if n=0 then l&lt;br /&gt;
  else g l (n-1) @ [n] ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ou encore&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec longueliste  n = &lt;br /&gt;
if n=0 &lt;br /&gt;
then []&lt;br /&gt;
else n::longueliste (n-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On peut tester les fonctions avec une liste de 10000 éléments.&lt;br /&gt;
&lt;br /&gt;
La fonction reverse met environ 15s alors que List.rev s&#039;execute immédiatement.&lt;br /&gt;
&lt;br /&gt;
Cela montre donc que List.rev est bien plus efficace que Reverse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Partie 3 : Deux algorithmes de tri pour les listes&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 1&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On programme une fonction insertion qui permet d&#039;insérer un élément à sa place&lt;br /&gt;
dans une liste triée.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec insertion l n =&lt;br /&gt;
  match l with&lt;br /&gt;
  []-&amp;gt;[n]&lt;br /&gt;
  |a::l&#039; -&amp;gt; if n&amp;lt;=a&lt;br /&gt;
    then n::l&lt;br /&gt;
    else a::(insertion l&#039; n) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 2&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On programme ensuite le tri par insertion.&lt;br /&gt;
&lt;br /&gt;
Le tri par insertion fonctionne de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
- la liste vide est triée,&lt;br /&gt;
&lt;br /&gt;
- pour trier la liste &amp;quot;a::l&amp;quot;, on commence par trier (récursivement) la liste l, puis on insère&lt;br /&gt;
l&#039;élément a dans le résultat.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec tri_insertion l =&lt;br /&gt;
 match l with&lt;br /&gt;
  []-&amp;gt;[]&lt;br /&gt;
  |a::l&#039; -&amp;gt; insertion (tri_insertion l&#039; ) a ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 3&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Maintenant, on programme une fonction fusionne qui permet de fusionner deux listes triées en une seule liste triée.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fusionne l1 l2 =&lt;br /&gt;
 match l1 with &lt;br /&gt;
 []-&amp;gt;l2&lt;br /&gt;
 |a::l&#039; -&amp;gt; begin&lt;br /&gt;
           match l2 with&lt;br /&gt;
            []-&amp;gt; l1&lt;br /&gt;
            |b::l&#039;&#039; -&amp;gt; if a&amp;lt;=b then ( a::fusionne l&#039; l2 ) &lt;br /&gt;
                               else ( b::fusionne l1 l&#039;&#039;) &lt;br /&gt;
&lt;br /&gt;
           end;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour éviter d&#039;imbriquer des &amp;quot;match&amp;quot;, on peut aussi filtrer directement la paire (l1,l2) : &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fusionnebis l1 l2 =&lt;br /&gt;
match (l1,l2) with&lt;br /&gt;
  ([],_)-&amp;gt;l2&lt;br /&gt;
  |(_,[])-&amp;gt;l1&lt;br /&gt;
  |(a::l&#039;, b::l2&#039;)-&amp;gt; &lt;br /&gt;
     if a &amp;lt; b&lt;br /&gt;
     then a::(fusionnebis l&#039; l2)&lt;br /&gt;
     else b::(fusionnebis l1 l2&#039;);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 4&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Puis une fonction sépare qui permet de séparer une liste quelconque en&lt;br /&gt;
deux listes de taille équivalente&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec separe l =&lt;br /&gt;
 match l with&lt;br /&gt;
 []-&amp;gt;([],[])&lt;br /&gt;
 |[a]-&amp;gt;([a],[])&lt;br /&gt;
 |a::b::l&#039; -&amp;gt; let t=separe l&#039; in (a::(fst t),b::(snd t)) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 5&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On doit maintenant programmer un deuxième type de tri : le tri par fusion.&lt;br /&gt;
&lt;br /&gt;
Le tri fusion fonctionne de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
- la liste vide est triée,&lt;br /&gt;
&lt;br /&gt;
- pour trier une liste non-vide, on sépare la liste en deux parties de longueur égale (à un&lt;br /&gt;
élément prêt), on trie (récursivement) ces deux listes, puis on fusionne les deux résultats.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec tri_fusion l =  &lt;br /&gt;
 match l with&lt;br /&gt;
 []-&amp;gt;[]&lt;br /&gt;
 |[a]-&amp;gt;[a]&lt;br /&gt;
 |_-&amp;gt;let t=separe l in&lt;br /&gt;
      fusionne (tri_fusion (fst t)) (tri_fusion (snd t)) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 6&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour comparer l&#039;efficacité des deux fonctions de tri, on utilise la même méthode que précédemment : &lt;br /&gt;
&lt;br /&gt;
On créé a l&#039;aide d&#039;un fonction une liste aléatoire de 10000 éléments, les éléments étant non triés.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec créé_list n = &lt;br /&gt;
 if n=0 then []&lt;br /&gt;
 else (Random.int n)::créé_list(n-1) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ensuite on trie cette liste avec les deux fonctions.&lt;br /&gt;
&lt;br /&gt;
Le tri_fusion renvoie instantanément une liste de 10000 élèments aléatoires triés. &lt;br /&gt;
&lt;br /&gt;
Le tri_insertion, quant à lui, prend plus d&#039;une dizaine de secondes.&lt;br /&gt;
&lt;br /&gt;
Cela semble logique dans le sens où le tri_fusion fait plusieurs calculs simultanés :&lt;br /&gt;
&lt;br /&gt;
il sépare chaque liste en 2 listes distinctes, qu&#039;il resépare en 2 listes distinctes, etc...&lt;br /&gt;
&lt;br /&gt;
Il effectue des calculs simultanés sur des plus petites listes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 7&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On souhaite trier une liste selon la hauteur des points c&#039;est-à-dire selon le deuxième élèment de la paire de flottants.&lt;br /&gt;
Pour cela, il faudrait faire un tri_fusion sur le 2eme élèment de la paire représentant les points&lt;br /&gt;
tout en sauvegardant le 1er élèment...&lt;br /&gt;
&lt;br /&gt;
On peut créer une fonction de tri par insertion générale, qui prend comme paramètre une autre fonction (qui sert à vérifier la comparaison de 2 éléments et rend true ou false) afin de choisir le tri que l&#039;on veut ( décroissant, croissant ... ) :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec insere comp n l = match l with&lt;br /&gt;
|  [] -&amp;gt; n::[]&lt;br /&gt;
|  a::l&#039; -&amp;gt;&lt;br /&gt;
   if comp n a then n :: l&lt;br /&gt;
   else a :: insere comp n l&#039; ;;&lt;br /&gt;
&lt;br /&gt;
let rec tri_insertion f   = function &lt;br /&gt;
|  [] -&amp;gt; []&lt;br /&gt;
|  a::l -&amp;gt; insere f a (tri_insertion f l) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il suffit alors a l&#039;utilisateur de définir la fonction f pour ensuite faire appel a tri_insertion.&lt;br /&gt;
&lt;br /&gt;
Par exemple, pour trier dans un ordre décroissant :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let dec a n  = if a&amp;gt;n then true&lt;br /&gt;
else false ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour trier une liste de paires, il faut créer une fonction qui compare les seconds membres ;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let paire a n  = if (snd a)&amp;lt;(snd n) then true&lt;br /&gt;
else false ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ici, les paires seront triées selon le second menbre dans l&#039;ordre croissant.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 8 ( Bonus )&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 --- à venir ---&lt;/div&gt;</summary>
		<author><name>Caroline</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO401_corr_TD_TP&amp;diff=3892</id>
		<title>INFO401 corr TD TP</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO401_corr_TD_TP&amp;diff=3892"/>
		<updated>2009-03-04T09:51:29Z</updated>

		<summary type="html">&lt;p&gt;Caroline : /* Le TP1 - début */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
Pour afficher correctement dans le wiki, allez voir un peu comment on fait. Vous pouvez regarder par exemple sur le [[INFO401 | wiki du cours]] ou directement sur des articles de [http://fr.wikipedia.org/wiki/Accueil Wikipedia]. La documentation de mediawiki se trouve [http://meta.wikimedia.org/wiki/Aide:Éditeur ici].&lt;br /&gt;
&lt;br /&gt;
Un truc important : pour rentrer du code Caml, il faut mettre les balises &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;...&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt; autour de votre code. Allez par exemple voir le début de la section sur [[#Le TD1 et le TP0 | le TD1 et TP0]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aller discuter des corrections dans les sujets de discussions associes...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Le TD1 et le TP0==&lt;br /&gt;
&lt;br /&gt;
Pour vous montrer un exemple de ce que j&#039;attends, voila la correction de la fonction factorielle. (C&#039;était facile...) J&#039;ai volontairement mis beaucoup de commentaires...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;La fonction factorielle (TD1, exercice 2, question 2)&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le but est de calculer la fonction &amp;lt;math&amp;gt;!n = 1\times2\times \cdots \times n&amp;lt;/math&amp;gt; par récurrence. La version typée est verbeuse de la fonction correspondante en Caml donne :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* fonction factorielle : c&#039;est la factorielle habituelle des mathématiciens... *)&lt;br /&gt;
let rec fact (n:int) : int =&lt;br /&gt;
  if (n&amp;gt;1)&lt;br /&gt;
  then  n * (fact (n-1))&lt;br /&gt;
  else 1      (* rq : pour que le programme ne boucle pas sur les valeurs négatives, on renvoie 1 dés que n&amp;lt;1 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme la fonction est récursive, il ne faut pas oublier le &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; au début de la définition.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On aurait pu faire une autre version, qui fonctionne différemment sur les nombres négatifs :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fact&#039; = function&lt;br /&gt;
   n when (n&amp;gt;0) -&amp;gt; n * fact&#039; (n-1)&lt;br /&gt;
 | n when (n&amp;lt;0) -&amp;gt; n * fact&#039; (n+1)&lt;br /&gt;
 | _ -&amp;gt; 1  (* si n n&#039;est ni plus petit que 0 ni plus grand que 0, n est égal à 0, et on renvoie donc 1 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J&#039;ai volontairement mis une version qui contient plusieurs choses que nous n&#039;avons pas encore vues en cours :&lt;br /&gt;
* utilisation de &amp;quot;&amp;lt;tt&amp;gt;function&amp;lt;/tt&amp;gt;&amp;quot; plutôt que &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;,&lt;br /&gt;
* le mot clé &amp;quot;&amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Vous devriez pouvoir comprendre ce que fait la fonction. Sinon, voici une version que vous auriez pu écrire :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fact_bis = fun n -&amp;gt;&lt;br /&gt;
  if (n=0)&lt;br /&gt;
  then 1&lt;br /&gt;
  else begin&lt;br /&gt;
    if (n&amp;gt;0)&lt;br /&gt;
    then n*fact_bis (n-1)&lt;br /&gt;
    else n*fact_bis (n+1)   (* dans ce cas, n est forcement négatif *)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Les fonctions sommes &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il s&#039;agit ici d&#039;écrire la fonction qui va additionner les carrés des entiers de 1 jusqu&#039;à un nombre donné.&lt;br /&gt;
&lt;br /&gt;
Cela donne :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec somme_carre b =&lt;br /&gt;
if (b=0) then 0&lt;br /&gt;
else (b*b) + somme_carre (b-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ensuite on nous demande de calculer la somme des cubes des entiers de 1 jusqu&#039;à un nombre donné. On pourrait faire le même programme en remplaçant b*b par b*b*b, mais on va définir une fonction puissance (car elle n&#039;existe pas d&#039;origine sous Caml), qui nous servira aussi pour la suite... :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec puissance x a =&lt;br /&gt;
if (a = 0) then 1&lt;br /&gt;
else x * puissance x (a-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On doit maintenant calculer la somme des &amp;lt;math&amp;gt;i^i&amp;lt;/math&amp;gt;, i variant de 1 à un nombre donné :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec somme_puissance b =&lt;br /&gt;
if (b=0) then 0&lt;br /&gt;
else (puissance b b) + somme_puissance (b-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On peut définir une unique fonction qui permettrait de faire toutes ces sommes, celle-ci aura pour argument une fonction quelconque :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec somme_fonction n f = (* f étant une fonction *)&lt;br /&gt;
if (n=0) then f 0&lt;br /&gt;
else f n + somme_fonction (n-1) f;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
cette fonction est de type &amp;quot;&amp;lt;tt&amp;gt;int -&amp;gt; fun -&amp;gt; int&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Nombres pairs et impairs (TP0 Partie 2 Question 2) &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il faut écrire les fonctions récursives pairs et impairs, qui renvoient vrai si le nombre est pair (respectivement impair) et faux si le nombre est impair (respectivement pair);&lt;br /&gt;
Ici nous devons déclarer simultanément les deux fonctions, car chacune fait appel à l&#039;autre lors de son exécution.&lt;br /&gt;
&lt;br /&gt;
Cela donne :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec pair n =&lt;br /&gt;
  if (n=0) then true&lt;br /&gt;
  else impair (n-1)&lt;br /&gt;
and impair n =&lt;br /&gt;
  if (n=0) then false&lt;br /&gt;
  else  pair (n-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Suite de Fibonacci &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La suite de fibonacci est tel que u&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;=0 u&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;=1 et u&amp;lt;sub&amp;gt;n+2&amp;lt;/sub&amp;gt;=u&amp;lt;sub&amp;gt;n+1&amp;lt;/sub&amp;gt;+u&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fib n =&lt;br /&gt;
if (n=0) then 0&lt;br /&gt;
else if (n=1) then 1&lt;br /&gt;
else fib (n-1) + fib (n-2);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La plus grande valeur que l&#039;on peut obtenir sans que cela soit trop long est 24157817, ce qui correspond à fib 37.&lt;br /&gt;
Nous trouvons qu&#039;il faut déjà 88 additions pour calculer fib 10.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Rq :&#039;&#039;&#039; fib de 37 prend effectivement beaucoup de temps. Il faut 39088168 additions avant d&#039;en arriver à bout. Il est possible de faire une version de Fibonacci qui va très vite et qui calcule &amp;lt;tt&amp;gt;fib 37&amp;lt;/tt&amp;gt; en seulement 36 additions...&lt;br /&gt;
: Comment ?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Dragon ! &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;i&amp;gt; Le dragon est une créature mythique, présente dans de nombreuses cultures.&lt;br /&gt;
  On peut déterminer deux grands types de dragons : le dragon occidental et le dragon oriental&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction dragon a pour but de dessiner un dragon, pour cela on utilise une fonction récursive qui admet pour argument le nombre n d&#039;itération de la fonction, et les coordonnées de 2 points. A chaque itération, la fonction calcule pour chaque segment, un nouveau point et le relie ensuite aux deux autres.&lt;br /&gt;
&lt;br /&gt;
On obtient en tout 2&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; segments entremêlés, qui forment un dragon.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s go !&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec dragon (n:int) (a:int) (b:int) (c:int) (d:int) : unit =&lt;br /&gt;
if (n = 0) then (moveto a b ; lineto c d)&lt;br /&gt;
               else begin&lt;br /&gt;
                      let x = (a+c+d-b)/2 in&lt;br /&gt;
                      let y = (b+d+a-c)/2 in&lt;br /&gt;
                      dragon (n-1) a b x y ;&lt;br /&gt;
                      dragon (n-1) c d x y&lt;br /&gt;
                    end ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Rq : &#039;&#039;&#039; votre version du dragon est bien, mais pas très précises. (Je chipote un peu...)  Pour les paramètres (&amp;lt;tt&amp;gt;dragon 11 100 100 400 400&amp;lt;/tt&amp;gt;), de nombreux carrés ne sont pas bien tracés.&lt;br /&gt;
:Comment expliquez-vous cela, et comment pouvez-vous le corriger ?&lt;br /&gt;
&lt;br /&gt;
::Pour améliorer la précision je suggère de passer les coordonnées en type Float. --[[Utilisateur:Nicolas|Nicolas]] 31 janvier 2009 à 11:42 (CET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Le TD2==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Exercice 1 : Tuples&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Question 4 :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
On définit la fonction curry par:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let curry (f: &#039;a * &#039;b -&amp;gt; &#039;c) : &#039;a -&amp;gt; &#039;b -&amp;gt; &#039;c&lt;br /&gt;
     = fun x y -&amp;gt; f(x,y);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ou encore en simplifiant:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let curry f x y = f(x,y);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On définit ensuite la fonction uncurry par:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry (f: &#039;a -&amp;gt; &#039;b -&amp;gt; &#039;c) : &#039;a * &#039;b -&amp;gt; &#039;c&lt;br /&gt;
     = fun x -&amp;gt; f (fst x) (snd x);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ou encore de trois autres manières plus simplifiées:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry f = fun x -&amp;gt; f (fst x) (snd x);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry f = fun x -&amp;gt; match x with (a,b) -&amp;gt; f a b;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry f = function (a,b) -&amp;gt; f a b;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Avantage de la première forme (à plusieurs arguments): Elle permet une application partielle: on peut appliquer cette fonction à une seule partie des arguments.&lt;br /&gt;
&lt;br /&gt;
Inconvénients de la seconde forme (à un argument): &lt;br /&gt;
*il faut faire appel à fst, snd;&lt;br /&gt;
*Caml doit séparer les paires: c&#039;est une perte de temps&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Question 5 :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
D&#039;après la fonction récursive Fibonacci définit par &amp;lt;br /&amp;gt;&lt;br /&gt;
f(0)=0 &amp;lt;br /&amp;gt;&lt;br /&gt;
f(1)=1 &amp;lt;br /&amp;gt;&lt;br /&gt;
f(n+2)=f(n+1)+f(n), &amp;lt;br /&amp;gt;&lt;br /&gt;
comment compter le nombre d&#039;appels récursifs en Caml? &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec fib n =&lt;br /&gt;
     if (n&amp;lt;2) then (n,0)&lt;br /&gt;
     else let t = fib (n-1) in&lt;br /&gt;
          let s = fib (n-2) in &lt;br /&gt;
     (fst t + fst s , snd t + snd s + 1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&#039;&#039;exemple : &#039;&#039;fib 10 = (55, 88) pour exécuter la fonction Fibonacci(10), il y a 88 appels récursifs nécessaires...&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Exercice 2 : Listes&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Question 5 :&#039;&#039;&#039;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
suite à l&#039;étude des fonctions &lt;br /&gt;
*longueur&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec longueur l=&lt;br /&gt;
     match l with&lt;br /&gt;
     [] -&amp;gt;0&lt;br /&gt;
     | _ :: l -&amp;gt; 1+longueur l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*applique&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec app f p =&lt;br /&gt;
     match p with &lt;br /&gt;
     [] -&amp;gt; []&lt;br /&gt;
     | a :: p -&amp;gt; f(a) :: app f p&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*concatene&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec cat l1 l2 =&lt;br /&gt;
     match l1 with&lt;br /&gt;
     [] -&amp;gt; l2&lt;br /&gt;
     | a :: l -&amp;gt; a :: (cat l l2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*renverse,&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec renverse l =&lt;br /&gt;
     match l with&lt;br /&gt;
     [] -&amp;gt; []&lt;br /&gt;
     | a :: l -&amp;gt; (renverse l)@[a]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
on remarque des similitudes. Ces fonctions ont le même schéma de base ( celui de la fonction reduit) &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec reduit l o f =&lt;br /&gt;
     match l with&lt;br /&gt;
     [] -&amp;gt; o&lt;br /&gt;
     | a :: l -&amp;gt; f a (reduit l o f)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&#039;&#039;NB :&#039;&#039; val reduit : &#039;a list -&amp;gt; &#039;b -&amp;gt; (&#039;a -&amp;gt; &#039;b -&amp;gt; &#039;b) -&amp;gt; &#039;b = &amp;lt;fun&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Question 6 :&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Reprogrammons les fonctions précédentes à partir de la fonction reduit ! &amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let longueur l =&lt;br /&gt;
     let f _ r = 1 + r in &lt;br /&gt;
     reduit l o f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let app g l =&lt;br /&gt;
     let f  &lt;br /&gt;
     reduit l [] f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let cat l1 l2 =&lt;br /&gt;
     let f a r = a :: r in  &lt;br /&gt;
     reduit l1 l2 f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let renverse l =&lt;br /&gt;
     let f r a = [r]@[a]  &lt;br /&gt;
     reduit l [] f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Le TP1 - début==&lt;br /&gt;
&lt;br /&gt;
Le sujet [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/0809/info401/tp1.pdf programmes récursifs, listes], au format pdf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Partie 1 : Quelques compléments sur les programmes récursifs&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, on travaille sur la fonction Fibonacci&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 1&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On commence par l&#039;utiliser sous la forme :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fib n =&lt;br /&gt;
if n&amp;lt;2&lt;br /&gt;
   then n&lt;br /&gt;
   else fib (n-1) + fib (n-2)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour comprendre ce qu&#039;il se passe, on trace la fonction à l&#039;aide de &amp;quot;#trace&amp;quot; pour fib 5&lt;br /&gt;
&lt;br /&gt;
fib &amp;lt;-- n veut dire que l&#039;on donne la valeur n à la fonction fib&lt;br /&gt;
&lt;br /&gt;
alors que fib --&amp;gt; n veut dire que fib renvoie n&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# fib 5 ;;&lt;br /&gt;
fib &amp;lt;-- 5&lt;br /&gt;
fib &amp;lt;-- 3&lt;br /&gt;
fib &amp;lt;-- 1&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib &amp;lt;-- 2&lt;br /&gt;
fib &amp;lt;-- 0&lt;br /&gt;
fib --&amp;gt; 0&lt;br /&gt;
...&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib &amp;lt;-- 2&lt;br /&gt;
fib &amp;lt;-- 0&lt;br /&gt;
fib --&amp;gt; 0&lt;br /&gt;
fib &amp;lt;-- 1&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib --&amp;gt; 2&lt;br /&gt;
fib --&amp;gt; 3&lt;br /&gt;
fib --&amp;gt; 5&lt;br /&gt;
- : int = 5&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On peut remarquer que la fonction calcule plusieurs fois le même fib n.&lt;br /&gt;
Une optimisation consisterait à garder certaines valeurs en mémoire.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 2&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On écrit fib2 de type &amp;quot;int -&amp;gt; int*int&amp;quot; qui renvoie le valeur de fib n (fst fib2 n) et fib n-1 (snd (fib2 n)) :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fib2 n = &lt;br /&gt;
if n&amp;lt;2 &lt;br /&gt;
   then (n,n-1)&lt;br /&gt;
   else let t = fib2 (n-1) in&lt;br /&gt;
      (fst(t)+snd(t),fst(t));;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 3&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour comparer les fonctions fib et fib2, on les trace pour n=7 :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# fib 7 ;;&lt;br /&gt;
fib &amp;lt;-- 7&lt;br /&gt;
fib &amp;lt;-- 5&lt;br /&gt;
fib &amp;lt;-- 3&lt;br /&gt;
fib &amp;lt;-- 1&lt;br /&gt;
...&lt;br /&gt;
fib --&amp;gt; 3&lt;br /&gt;
fib --&amp;gt; 5&lt;br /&gt;
fib --&amp;gt; 8&lt;br /&gt;
fib --&amp;gt; 13&lt;br /&gt;
- : int = 13&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# fib2 7 ;;&lt;br /&gt;
fib2 &amp;lt;-- 7&lt;br /&gt;
fib2 &amp;lt;-- 6&lt;br /&gt;
fib2 &amp;lt;-- 5&lt;br /&gt;
fib2 &amp;lt;-- 4&lt;br /&gt;
fib2 &amp;lt;-- 3&lt;br /&gt;
fib2 &amp;lt;-- 2&lt;br /&gt;
fib2 &amp;lt;-- 1&lt;br /&gt;
fib2 --&amp;gt; (1, 0)&lt;br /&gt;
fib2 --&amp;gt; (1, 1)&lt;br /&gt;
fib2 --&amp;gt; (2, 1)&lt;br /&gt;
fib2 --&amp;gt; (3, 2)&lt;br /&gt;
fib2 --&amp;gt; (5, 3)&lt;br /&gt;
fib2 --&amp;gt; (8, 5)&lt;br /&gt;
fib2 --&amp;gt; (13, 8)&lt;br /&gt;
- : int * int = (13, 8)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
On remarque que fib2 fait 14 calculs alors que fib en 81 pour n=7.&lt;br /&gt;
Afin de retourner uniquement la valeur de fib n on définit une nouvelle fonction, beaucoup plus rapide que fib, &lt;br /&gt;
en prenant le premier élèment de la paire constituant fib2 n.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 4 ( Bonus )&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On veut créer fib3 de type int-&amp;gt;int-&amp;gt;int-&amp;gt;int tel que :&lt;br /&gt;
&lt;br /&gt;
- son premier argument est l&#039;entier n pour fibonacci de n&lt;br /&gt;
&lt;br /&gt;
- les 2 autres arguments sont des accumulateurs qui permettent de conserver des valeurs successives ( pour i-1 et i )&lt;br /&gt;
&lt;br /&gt;
 --- à venir ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Partie 2 : Manipulation des listes&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 1&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voici quelque fonctions d&#039;abord en définition directe, puis en utiliser la fonction List.fold right&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec longueur l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
|a::l&#039;-&amp;gt;1 + (longueur l&#039;)&lt;br /&gt;
&lt;br /&gt;
	let rec applique f l = match l with&lt;br /&gt;
	[]-&amp;gt;[]&lt;br /&gt;
	|a::l -&amp;gt; ( f a )::( applique f l )&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec applique f l = match l with&lt;br /&gt;
[]-&amp;gt;[]&lt;br /&gt;
|a::l -&amp;gt; ( f a )::( applique f l )&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec concatene l l&#039; = match l with&lt;br /&gt;
[]-&amp;gt;l&#039;&lt;br /&gt;
|a::l-&amp;gt;a::(concatene l l&#039;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let longueur_bis l = let f a r = 1 + r in List.fold_right l o f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let applique_bis f l = let f&#039; a r = ( f a )::r in List.fold_right l [] f&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let concatene_bis l1 l2 = let f a r = a::r in List.fold_right l1 l2 f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 2&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voici la fonction reverse telle qu&#039;on l&#039;a écrite dans le TD&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec reverse l = &lt;br /&gt;
  match l with&lt;br /&gt;
  []-&amp;gt;[]&lt;br /&gt;
  |a::l -&amp;gt; (reverse l)@[a] ;; &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour la comparer avec List.rev, on va regarder le temps d&#039;exécution sur une très grande liste.&lt;br /&gt;
&lt;br /&gt;
Pour cela, on créé une fonction qui fabrique une liste de n valeurs :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec liste_ordonnée l n  = &lt;br /&gt;
  if n=0 then l&lt;br /&gt;
  else g l (n-1) @ [n] ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ou encore&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec longueliste  n = &lt;br /&gt;
if n=0 &lt;br /&gt;
then []&lt;br /&gt;
else n::longueliste (n-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On peut tester les fonctions avec une liste de 10000 éléments.&lt;br /&gt;
&lt;br /&gt;
La fonction reverse met environ 15s alors que List.rev s&#039;execute immédiatement.&lt;br /&gt;
&lt;br /&gt;
Cela montre donc que List.rev est bien plus efficace que Reverse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Partie 3 : Deux algorithmes de tri pour les listes&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 1&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On programme une fonction insertion qui permet d&#039;insérer un élément à sa place&lt;br /&gt;
dans une liste triée.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec insertion l n =&lt;br /&gt;
  match l with&lt;br /&gt;
  []-&amp;gt;[n]&lt;br /&gt;
  |a::l&#039; -&amp;gt; if n&amp;lt;=a&lt;br /&gt;
    then n::l&lt;br /&gt;
    else a::(insertion l&#039; n) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 2&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On programme ensuite le tri par insertion.&lt;br /&gt;
&lt;br /&gt;
Le tri par insertion fonctionne de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
- la liste vide est triée,&lt;br /&gt;
&lt;br /&gt;
- pour trier la liste &amp;quot;a::l&amp;quot;, on commence par trier (récursivement) la liste l, puis on insère&lt;br /&gt;
l&#039;élément a dans le résultat.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec tri_insertion l =&lt;br /&gt;
 match l with&lt;br /&gt;
  []-&amp;gt;[]&lt;br /&gt;
  |a::l&#039; -&amp;gt; insertion (tri_insertion l&#039; ) a ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 3&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Maintenant, on programme une fonction fusionne qui permet de fusionner deux listes triées en une seule liste triée.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fusionne l1 l2 =&lt;br /&gt;
 match l1 with &lt;br /&gt;
 []-&amp;gt;l2&lt;br /&gt;
 |a::l&#039; -&amp;gt; begin&lt;br /&gt;
           match l2 with&lt;br /&gt;
            []-&amp;gt; l1&lt;br /&gt;
            |b::l&#039;&#039; -&amp;gt; if a&amp;lt;=b then ( a::fusionne l&#039; l2 ) &lt;br /&gt;
                               else ( b::fusionne l1 l&#039;&#039;) &lt;br /&gt;
&lt;br /&gt;
           end;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour éviter d&#039;imbriquer des &amp;quot;match&amp;quot;, on peut aussi filtrer directement la paire (l1,l2) : &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fusionnebis l1 l2 =&lt;br /&gt;
match (l1,l2) with&lt;br /&gt;
  ([],_)-&amp;gt;l2&lt;br /&gt;
  |(_,[])-&amp;gt;l1&lt;br /&gt;
  |(a::l&#039;, b::l2&#039;)-&amp;gt; &lt;br /&gt;
     if a &amp;lt; b&lt;br /&gt;
     then a::(fusionnebis l&#039; l2)&lt;br /&gt;
     else b::(fusionnebis l1 l2&#039;);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 4&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Puis une fonction sépare qui permet de séparer une liste quelconque en&lt;br /&gt;
deux listes de taille équivalente&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec separe l =&lt;br /&gt;
 match l with&lt;br /&gt;
 []-&amp;gt;([],[])&lt;br /&gt;
 |[a]-&amp;gt;([a],[])&lt;br /&gt;
 |a::b::l&#039; -&amp;gt; let t=separe l&#039; in (a::(fst t),b::(snd t)) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 5&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On doit maintenant programmer un deuxième type de tri : le tri par fusion.&lt;br /&gt;
&lt;br /&gt;
Le tri fusion fonctionne de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
- la liste vide est triée,&lt;br /&gt;
&lt;br /&gt;
- pour trier une liste non-vide, on sépare la liste en deux parties de longueur égale (à un&lt;br /&gt;
élément prêt), on trie (récursivement) ces deux listes, puis on fusionne les deux résultats.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec tri_fusion l =  &lt;br /&gt;
 match l with&lt;br /&gt;
 []-&amp;gt;[]&lt;br /&gt;
 |[a]-&amp;gt;[a]&lt;br /&gt;
 |_-&amp;gt;let t=separe l in&lt;br /&gt;
      fusionne (tri_fusion (fst t)) (tri_fusion (snd t)) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 6&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour comparer l&#039;efficacité des deux fonctions de tri, on utilise la même méthode que précédemment : &lt;br /&gt;
&lt;br /&gt;
On créé a l&#039;aide d&#039;un fonction une liste aléatoire de 10000 éléments, les éléments étant non triés.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec créé_list n = &lt;br /&gt;
 if n=0 then []&lt;br /&gt;
 else (Random.int n)::créé_list(n-1) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ensuite on trie cette liste avec les deux fonctions.&lt;br /&gt;
&lt;br /&gt;
Le tri_fusion renvoie instantanément une liste de 10000 élèments aléatoires triés. &lt;br /&gt;
&lt;br /&gt;
Le tri_insertion, quant à lui, prend plus d&#039;une dizaine de secondes.&lt;br /&gt;
&lt;br /&gt;
Cela semble logique dans le sens où le tri_fusion fait plusieurs calculs simultanés :&lt;br /&gt;
&lt;br /&gt;
il sépare chaque liste en 2 listes distinctes, qu&#039;il resépare en 2 listes distinctes, etc...&lt;br /&gt;
&lt;br /&gt;
Il effectue des calculs simultanés sur des plus petites listes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 7&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On souhaite trier une liste selon la hauteur des points c&#039;est-à-dire selon le deuxième élèment de la paire de flottants.&lt;br /&gt;
Pour cela, il faudrait faire un tri_fusion sur le 2eme élèment de la paire représentant les points&lt;br /&gt;
tout en sauvegardant le 1er élèment...&lt;br /&gt;
&lt;br /&gt;
 --- à venir ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 8 ( Bonus )&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 --- à venir ---&lt;/div&gt;</summary>
		<author><name>Caroline</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO401_corr_TD_TP&amp;diff=3891</id>
		<title>INFO401 corr TD TP</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO401_corr_TD_TP&amp;diff=3891"/>
		<updated>2009-03-04T09:38:52Z</updated>

		<summary type="html">&lt;p&gt;Caroline : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
Pour afficher correctement dans le wiki, allez voir un peu comment on fait. Vous pouvez regarder par exemple sur le [[INFO401 | wiki du cours]] ou directement sur des articles de [http://fr.wikipedia.org/wiki/Accueil Wikipedia]. La documentation de mediawiki se trouve [http://meta.wikimedia.org/wiki/Aide:Éditeur ici].&lt;br /&gt;
&lt;br /&gt;
Un truc important : pour rentrer du code Caml, il faut mettre les balises &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;...&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt; autour de votre code. Allez par exemple voir le début de la section sur [[#Le TD1 et le TP0 | le TD1 et TP0]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aller discuter des corrections dans les sujets de discussions associes...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Le TD1 et le TP0==&lt;br /&gt;
&lt;br /&gt;
Pour vous montrer un exemple de ce que j&#039;attends, voila la correction de la fonction factorielle. (C&#039;était facile...) J&#039;ai volontairement mis beaucoup de commentaires...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;La fonction factorielle (TD1, exercice 2, question 2)&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le but est de calculer la fonction &amp;lt;math&amp;gt;!n = 1\times2\times \cdots \times n&amp;lt;/math&amp;gt; par récurrence. La version typée est verbeuse de la fonction correspondante en Caml donne :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* fonction factorielle : c&#039;est la factorielle habituelle des mathématiciens... *)&lt;br /&gt;
let rec fact (n:int) : int =&lt;br /&gt;
  if (n&amp;gt;1)&lt;br /&gt;
  then  n * (fact (n-1))&lt;br /&gt;
  else 1      (* rq : pour que le programme ne boucle pas sur les valeurs négatives, on renvoie 1 dés que n&amp;lt;1 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme la fonction est récursive, il ne faut pas oublier le &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; au début de la définition.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On aurait pu faire une autre version, qui fonctionne différemment sur les nombres négatifs :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fact&#039; = function&lt;br /&gt;
   n when (n&amp;gt;0) -&amp;gt; n * fact&#039; (n-1)&lt;br /&gt;
 | n when (n&amp;lt;0) -&amp;gt; n * fact&#039; (n+1)&lt;br /&gt;
 | _ -&amp;gt; 1  (* si n n&#039;est ni plus petit que 0 ni plus grand que 0, n est égal à 0, et on renvoie donc 1 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J&#039;ai volontairement mis une version qui contient plusieurs choses que nous n&#039;avons pas encore vues en cours :&lt;br /&gt;
* utilisation de &amp;quot;&amp;lt;tt&amp;gt;function&amp;lt;/tt&amp;gt;&amp;quot; plutôt que &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;,&lt;br /&gt;
* le mot clé &amp;quot;&amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Vous devriez pouvoir comprendre ce que fait la fonction. Sinon, voici une version que vous auriez pu écrire :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fact_bis = fun n -&amp;gt;&lt;br /&gt;
  if (n=0)&lt;br /&gt;
  then 1&lt;br /&gt;
  else begin&lt;br /&gt;
    if (n&amp;gt;0)&lt;br /&gt;
    then n*fact_bis (n-1)&lt;br /&gt;
    else n*fact_bis (n+1)   (* dans ce cas, n est forcement négatif *)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Les fonctions sommes &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il s&#039;agit ici d&#039;écrire la fonction qui va additionner les carrés des entiers de 1 jusqu&#039;à un nombre donné.&lt;br /&gt;
&lt;br /&gt;
Cela donne :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec somme_carre b =&lt;br /&gt;
if (b=0) then 0&lt;br /&gt;
else (b*b) + somme_carre (b-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ensuite on nous demande de calculer la somme des cubes des entiers de 1 jusqu&#039;à un nombre donné. On pourrait faire le même programme en remplaçant b*b par b*b*b, mais on va définir une fonction puissance (car elle n&#039;existe pas d&#039;origine sous Caml), qui nous servira aussi pour la suite... :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec puissance x a =&lt;br /&gt;
if (a = 0) then 1&lt;br /&gt;
else x * puissance x (a-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On doit maintenant calculer la somme des &amp;lt;math&amp;gt;i^i&amp;lt;/math&amp;gt;, i variant de 1 à un nombre donné :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec somme_puissance b =&lt;br /&gt;
if (b=0) then 0&lt;br /&gt;
else (puissance b b) + somme_puissance (b-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On peut définir une unique fonction qui permettrait de faire toutes ces sommes, celle-ci aura pour argument une fonction quelconque :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec somme_fonction n f = (* f étant une fonction *)&lt;br /&gt;
if (n=0) then f 0&lt;br /&gt;
else f n + somme_fonction (n-1) f;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
cette fonction est de type &amp;quot;&amp;lt;tt&amp;gt;int -&amp;gt; fun -&amp;gt; int&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Nombres pairs et impairs (TP0 Partie 2 Question 2) &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il faut écrire les fonctions récursives pairs et impairs, qui renvoient vrai si le nombre est pair (respectivement impair) et faux si le nombre est impair (respectivement pair);&lt;br /&gt;
Ici nous devons déclarer simultanément les deux fonctions, car chacune fait appel à l&#039;autre lors de son exécution.&lt;br /&gt;
&lt;br /&gt;
Cela donne :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec pair n =&lt;br /&gt;
  if (n=0) then true&lt;br /&gt;
  else impair (n-1)&lt;br /&gt;
and impair n =&lt;br /&gt;
  if (n=0) then false&lt;br /&gt;
  else  pair (n-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Suite de Fibonacci &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La suite de fibonacci est tel que u&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;=0 u&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;=1 et u&amp;lt;sub&amp;gt;n+2&amp;lt;/sub&amp;gt;=u&amp;lt;sub&amp;gt;n+1&amp;lt;/sub&amp;gt;+u&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fib n =&lt;br /&gt;
if (n=0) then 0&lt;br /&gt;
else if (n=1) then 1&lt;br /&gt;
else fib (n-1) + fib (n-2);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La plus grande valeur que l&#039;on peut obtenir sans que cela soit trop long est 24157817, ce qui correspond à fib 37.&lt;br /&gt;
Nous trouvons qu&#039;il faut déjà 88 additions pour calculer fib 10.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Rq :&#039;&#039;&#039; fib de 37 prend effectivement beaucoup de temps. Il faut 39088168 additions avant d&#039;en arriver à bout. Il est possible de faire une version de Fibonacci qui va très vite et qui calcule &amp;lt;tt&amp;gt;fib 37&amp;lt;/tt&amp;gt; en seulement 36 additions...&lt;br /&gt;
: Comment ?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt; Dragon ! &amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;i&amp;gt; Le dragon est une créature mythique, présente dans de nombreuses cultures.&lt;br /&gt;
  On peut déterminer deux grands types de dragons : le dragon occidental et le dragon oriental&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction dragon a pour but de dessiner un dragon, pour cela on utilise une fonction récursive qui admet pour argument le nombre n d&#039;itération de la fonction, et les coordonnées de 2 points. A chaque itération, la fonction calcule pour chaque segment, un nouveau point et le relie ensuite aux deux autres.&lt;br /&gt;
&lt;br /&gt;
On obtient en tout 2&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; segments entremêlés, qui forment un dragon.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s go !&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec dragon (n:int) (a:int) (b:int) (c:int) (d:int) : unit =&lt;br /&gt;
if (n = 0) then (moveto a b ; lineto c d)&lt;br /&gt;
               else begin&lt;br /&gt;
                      let x = (a+c+d-b)/2 in&lt;br /&gt;
                      let y = (b+d+a-c)/2 in&lt;br /&gt;
                      dragon (n-1) a b x y ;&lt;br /&gt;
                      dragon (n-1) c d x y&lt;br /&gt;
                    end ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Rq : &#039;&#039;&#039; votre version du dragon est bien, mais pas très précises. (Je chipote un peu...)  Pour les paramètres (&amp;lt;tt&amp;gt;dragon 11 100 100 400 400&amp;lt;/tt&amp;gt;), de nombreux carrés ne sont pas bien tracés.&lt;br /&gt;
:Comment expliquez-vous cela, et comment pouvez-vous le corriger ?&lt;br /&gt;
&lt;br /&gt;
::Pour améliorer la précision je suggère de passer les coordonnées en type Float. --[[Utilisateur:Nicolas|Nicolas]] 31 janvier 2009 à 11:42 (CET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Le TD2==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Exercice 1 : Tuples&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Question 4 :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
On définit la fonction curry par:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let curry (f: &#039;a * &#039;b -&amp;gt; &#039;c) : &#039;a -&amp;gt; &#039;b -&amp;gt; &#039;c&lt;br /&gt;
     = fun x y -&amp;gt; f(x,y);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ou encore en simplifiant:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let curry f x y = f(x,y);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On définit ensuite la fonction uncurry par:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry (f: &#039;a -&amp;gt; &#039;b -&amp;gt; &#039;c) : &#039;a * &#039;b -&amp;gt; &#039;c&lt;br /&gt;
     = fun x -&amp;gt; f (fst x) (snd x);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ou encore de trois autres manières plus simplifiées:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry f = fun x -&amp;gt; f (fst x) (snd x);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry f = fun x -&amp;gt; match x with (a,b) -&amp;gt; f a b;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 Let uncurry f = function (a,b) -&amp;gt; f a b;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Avantage de la première forme (à plusieurs arguments): Elle permet une application partielle: on peut appliquer cette fonction à une seule partie des arguments.&lt;br /&gt;
&lt;br /&gt;
Inconvénients de la seconde forme (à un argument): &lt;br /&gt;
*il faut faire appel à fst, snd;&lt;br /&gt;
*Caml doit séparer les paires: c&#039;est une perte de temps&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Question 5 :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
D&#039;après la fonction récursive Fibonacci définit par &amp;lt;br /&amp;gt;&lt;br /&gt;
f(0)=0 &amp;lt;br /&amp;gt;&lt;br /&gt;
f(1)=1 &amp;lt;br /&amp;gt;&lt;br /&gt;
f(n+2)=f(n+1)+f(n), &amp;lt;br /&amp;gt;&lt;br /&gt;
comment compter le nombre d&#039;appels récursifs en Caml? &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec fib n =&lt;br /&gt;
     if (n&amp;lt;2) then (n,0)&lt;br /&gt;
     else let t = fib (n-1) in&lt;br /&gt;
          let s = fib (n-2) in &lt;br /&gt;
     (fst t + fst s , snd t + snd s + 1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&#039;&#039;exemple : &#039;&#039;fib 10 = (55, 88) pour exécuter la fonction Fibonacci(10), il y a 88 appels récursifs nécessaires...&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Exercice 2 : Listes&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Question 5 :&#039;&#039;&#039;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
suite à l&#039;étude des fonctions &lt;br /&gt;
*longueur&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec longueur l=&lt;br /&gt;
     match l with&lt;br /&gt;
     [] -&amp;gt;0&lt;br /&gt;
     | _ :: l -&amp;gt; 1+longueur l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*applique&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec app f p =&lt;br /&gt;
     match p with &lt;br /&gt;
     [] -&amp;gt; []&lt;br /&gt;
     | a :: p -&amp;gt; f(a) :: app f p&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*concatene&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec cat l1 l2 =&lt;br /&gt;
     match l1 with&lt;br /&gt;
     [] -&amp;gt; l2&lt;br /&gt;
     | a :: l -&amp;gt; a :: (cat l l2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*renverse,&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec renverse l =&lt;br /&gt;
     match l with&lt;br /&gt;
     [] -&amp;gt; []&lt;br /&gt;
     | a :: l -&amp;gt; (renverse l)@[a]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
on remarque des similitudes. Ces fonctions ont le même schéma de base ( celui de la fonction reduit) &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rec reduit l o f =&lt;br /&gt;
     match l with&lt;br /&gt;
     [] -&amp;gt; o&lt;br /&gt;
     | a :: l -&amp;gt; f a (reduit l o f)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&#039;&#039;NB :&#039;&#039; val reduit : &#039;a list -&amp;gt; &#039;b -&amp;gt; (&#039;a -&amp;gt; &#039;b -&amp;gt; &#039;b) -&amp;gt; &#039;b = &amp;lt;fun&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Question 6 :&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Reprogrammons les fonctions précédentes à partir de la fonction reduit ! &amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let longueur l =&lt;br /&gt;
     let f _ r = 1 + r in &lt;br /&gt;
     reduit l o f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let app g l =&lt;br /&gt;
     let f  &lt;br /&gt;
     reduit l [] f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let cat l1 l2 =&lt;br /&gt;
     let f a r = a :: r in  &lt;br /&gt;
     reduit l1 l2 f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt; &lt;br /&gt;
 let renverse l =&lt;br /&gt;
     let f r a = [r]@[a]  &lt;br /&gt;
     reduit l [] f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Le TP1 - début==&lt;br /&gt;
&lt;br /&gt;
Le sujet [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/0809/info401/tp1.pdf programmes récursifs, listes], au format pdf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Partie 1 : Quelques compléments sur les programmes récursifs&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, on travaille sur la fonction Fibonacci&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 1&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On commence par l&#039;utiliser sous la forme :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fib n =&lt;br /&gt;
if n&amp;lt;2&lt;br /&gt;
   then n&lt;br /&gt;
   else fib (n-1) + fib (n-2)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour comprendre ce qu&#039;il se passe, on trace la fonction à l&#039;aide de &amp;quot;#trace&amp;quot; pour fib 5&lt;br /&gt;
&lt;br /&gt;
fib &amp;lt;-- n veut dire que l&#039;on donne la valeur n à la fonction fib&lt;br /&gt;
&lt;br /&gt;
alors que fib --&amp;gt; n veut dire que fib renvoie n&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# fib 5 ;;&lt;br /&gt;
fib &amp;lt;-- 5&lt;br /&gt;
fib &amp;lt;-- 3&lt;br /&gt;
fib &amp;lt;-- 1&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib &amp;lt;-- 2&lt;br /&gt;
fib &amp;lt;-- 0&lt;br /&gt;
fib --&amp;gt; 0&lt;br /&gt;
...&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib &amp;lt;-- 2&lt;br /&gt;
fib &amp;lt;-- 0&lt;br /&gt;
fib --&amp;gt; 0&lt;br /&gt;
fib &amp;lt;-- 1&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib --&amp;gt; 1&lt;br /&gt;
fib --&amp;gt; 2&lt;br /&gt;
fib --&amp;gt; 3&lt;br /&gt;
fib --&amp;gt; 5&lt;br /&gt;
- : int = 5&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On peut remarquer que la fonction calcule plusieurs fois le même fib n.&lt;br /&gt;
Une optimisation consisterait à garder certaines valeurs en mémoire.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 2&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On écrit fib2 de type &amp;quot;int -&amp;gt; int*int&amp;quot; qui renvoie le valeur de fib n (fst fib2 n) et fib n-1 (snd (fib2 n)) :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fib2 n = &lt;br /&gt;
if n&amp;lt;2 &lt;br /&gt;
   then (n,n-1)&lt;br /&gt;
   else let t = fib2 (n-1) in&lt;br /&gt;
      (fst(t)+snd(t),fst(t));;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 3&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour comparer les fonctions fib et fib2, on les trace pour n=7 :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# fib 7 ;;&lt;br /&gt;
fib &amp;lt;-- 7&lt;br /&gt;
fib &amp;lt;-- 5&lt;br /&gt;
fib &amp;lt;-- 3&lt;br /&gt;
fib &amp;lt;-- 1&lt;br /&gt;
...&lt;br /&gt;
fib --&amp;gt; 3&lt;br /&gt;
fib --&amp;gt; 5&lt;br /&gt;
fib --&amp;gt; 8&lt;br /&gt;
fib --&amp;gt; 13&lt;br /&gt;
- : int = 13&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# fib2 7 ;;&lt;br /&gt;
fib2 &amp;lt;-- 7&lt;br /&gt;
fib2 &amp;lt;-- 6&lt;br /&gt;
fib2 &amp;lt;-- 5&lt;br /&gt;
fib2 &amp;lt;-- 4&lt;br /&gt;
fib2 &amp;lt;-- 3&lt;br /&gt;
fib2 &amp;lt;-- 2&lt;br /&gt;
fib2 &amp;lt;-- 1&lt;br /&gt;
fib2 --&amp;gt; (1, 0)&lt;br /&gt;
fib2 --&amp;gt; (1, 1)&lt;br /&gt;
fib2 --&amp;gt; (2, 1)&lt;br /&gt;
fib2 --&amp;gt; (3, 2)&lt;br /&gt;
fib2 --&amp;gt; (5, 3)&lt;br /&gt;
fib2 --&amp;gt; (8, 5)&lt;br /&gt;
fib2 --&amp;gt; (13, 8)&lt;br /&gt;
- : int * int = (13, 8)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
On remarque que fib2 fait 14 calculs alors que fib en 81 pour n=7.&lt;br /&gt;
Afin de retourner uniquement la valeur de fib n on définit une nouvelle fonction, beaucoup plus rapide que fib, &lt;br /&gt;
en prenant le premier élèment de la paire constituant fib2 n.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 4 ( Bonus )&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On veut créer fib3 de type int-&amp;gt;int-&amp;gt;int-&amp;gt;int tel que :&lt;br /&gt;
&lt;br /&gt;
- son premier argument est l&#039;entier n pour fibonacci de n&lt;br /&gt;
&lt;br /&gt;
- les 2 autres arguments sont des accumulateurs qui permettent de conserver des valeurs successives ( pour i-1 et i )&lt;br /&gt;
&lt;br /&gt;
 --- à venir ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Partie 2 : Manipulation des listes&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 1&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voici quelque fonctions d&#039;abord en définition directe, puis en utiliser la fonction List.fold right&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec longueur l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
|a::l&#039;-&amp;gt;1 + (longueur l&#039;)&lt;br /&gt;
&lt;br /&gt;
	let rec applique f l = match l with&lt;br /&gt;
	[]-&amp;gt;[]&lt;br /&gt;
	|a::l -&amp;gt; ( f a )::( applique f l )&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec applique f l = match l with&lt;br /&gt;
[]-&amp;gt;[]&lt;br /&gt;
|a::l -&amp;gt; ( f a )::( applique f l )&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec concatene l l&#039; = match l with&lt;br /&gt;
[]-&amp;gt;l&#039;&lt;br /&gt;
|a::l-&amp;gt;a::(concatene l l&#039;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let longueur_bis l = let f a r = 1 + r in List.fold_right l o f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let applique_bis f l = let f&#039; a r = ( f a )::r in List.fold_right l [] f&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let concatene_bis l1 l2 = let f a r = a::r in List.fold_right l1 l2 f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 2&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voici la fonction reverse telle qu&#039;on l&#039;a écrite dans le TD&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec reverse l = &lt;br /&gt;
  match l with&lt;br /&gt;
  []-&amp;gt;[]&lt;br /&gt;
  |a::l -&amp;gt; (reverse l)@[a] ;; &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour la comparer avec List.rev, on va regarder le temps d&#039;exécution sur une très grande liste.&lt;br /&gt;
&lt;br /&gt;
Pour cela, on créé une fonction qui fabrique une liste de n valeurs :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec liste_ordonnée l n  = &lt;br /&gt;
  if n=0 then l&lt;br /&gt;
  else g l (n-1) @ [n] ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ou encore&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec longueliste  n = &lt;br /&gt;
if n=0 &lt;br /&gt;
then []&lt;br /&gt;
else n::longueliste (n-1);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On peut tester les fonctions avec une liste de 10000 éléments.&lt;br /&gt;
&lt;br /&gt;
La fonction reverse met environ 15s alors que List.rev s&#039;execute immédiatement.&lt;br /&gt;
&lt;br /&gt;
Cela montre donc que List.rev est bien plus efficace que Reverse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Partie 3 : Deux algorithmes de tri pour les listes&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 1&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On programme une fonction insertion qui permet d&#039;insérer un élément à sa place&lt;br /&gt;
dans une liste triée.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec insertion l n =&lt;br /&gt;
  match l with&lt;br /&gt;
  []-&amp;gt;[n]&lt;br /&gt;
  |a::l&#039; -&amp;gt; if n&amp;lt;=a&lt;br /&gt;
    then n::l&lt;br /&gt;
    else a::(insertion l&#039; n) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 2&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On programme ensuite le tri par insertion.&lt;br /&gt;
&lt;br /&gt;
Le tri par insertion fonctionne de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
- la liste vide est triée,&lt;br /&gt;
&lt;br /&gt;
- pour trier la liste &amp;quot;a::l&amp;quot;, on commence par trier (récursivement) la liste l, puis on insère&lt;br /&gt;
l&#039;élément a dans le résultat.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec tri_insertion l =&lt;br /&gt;
 match l with&lt;br /&gt;
  []-&amp;gt;[]&lt;br /&gt;
  |a::l&#039; -&amp;gt; insertion (tri_insertion l&#039; ) a ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 3&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Maintenant, on programme une fonction fusionne qui permet de fusionner deux listes triées en une seule liste triée.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fusionne l1 l2 =&lt;br /&gt;
 match l1 with &lt;br /&gt;
 []-&amp;gt;l2&lt;br /&gt;
 |a::l&#039; -&amp;gt; begin&lt;br /&gt;
           match l2 with&lt;br /&gt;
            []-&amp;gt; l1&lt;br /&gt;
            |b::l&#039;&#039; -&amp;gt; if a&amp;lt;=b then ( a::fusionne l&#039; l2 ) &lt;br /&gt;
                               else ( b::fusionne l1 l&#039;&#039;) &lt;br /&gt;
&lt;br /&gt;
           end;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour éviter d&#039;imbriquer des &amp;quot;match&amp;quot;, on peut aussi filtrer directement la paire (l1,l2) : &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec fusionnebis l1 l2 =&lt;br /&gt;
match (l1,l2) with&lt;br /&gt;
  ([],_)-&amp;gt;l2&lt;br /&gt;
  |(_,[])-&amp;gt;l1&lt;br /&gt;
  |(a::l&#039;, b::l2&#039;)-&amp;gt; &lt;br /&gt;
     if a &amp;lt; b&lt;br /&gt;
     then a::(fusionnebis l&#039; l2)&lt;br /&gt;
     else b::(fusionnebis l1 l2&#039;);;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 4&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Puis une fonction sépare qui permet de séparer une liste quelconque en&lt;br /&gt;
deux listes de taille équivalente&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec separe l =&lt;br /&gt;
 match l with&lt;br /&gt;
 []-&amp;gt;([],[])&lt;br /&gt;
 |[a]-&amp;gt;([a],[])&lt;br /&gt;
 |a::b::l&#039; -&amp;gt; let t=separe l&#039; in (a::(fst t),b::(snd t)) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 5&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On doit maintenant programmer un deuxième type de tri : le tri par fusion.&lt;br /&gt;
&lt;br /&gt;
Le tri fusion fonctionne de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
- la liste vide est triée,&lt;br /&gt;
&lt;br /&gt;
- pour trier une liste non-vide, on sépare la liste en deux parties de longueur égale (à un&lt;br /&gt;
élément prêt), on trie (récursivement) ces deux listes, puis on fusionne les deux résultats.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec tri_fusion l =  &lt;br /&gt;
 match l with&lt;br /&gt;
 []-&amp;gt;[]&lt;br /&gt;
 |[a]-&amp;gt;[a]&lt;br /&gt;
 |_-&amp;gt;let t=separe l in&lt;br /&gt;
      fusionne (tri_fusion (fst t)) (tri_fusion (snd t)) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 6&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour comparer l&#039;efficacité des deux fonctions de tri, on utilise la même méthode que précédemment : &lt;br /&gt;
&lt;br /&gt;
On créé a l&#039;aide d&#039;un fonction une liste aléatoire de 10000 éléments, les éléments étant non triés.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec créé_list n = &lt;br /&gt;
 if n=0 then []&lt;br /&gt;
 else (Random.int n)::créé_list(n-1) ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ensuite on trie cette liste avec les deux fonctions.&lt;br /&gt;
&lt;br /&gt;
Le tri_fusion renvoie instantanément une liste de 10000 élèments aléatoires triés. &lt;br /&gt;
Le tri_insertion, quant à lui, prend plus d&#039;une dizaine de secondes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Cela semble logique dans le sens où le tri_fusion fait plusieurs calculs simultanés :&lt;br /&gt;
il sépare chaque liste en 2 listes distinctes, qu&#039;il resépare en 2 listes distinctes, etc...&lt;br /&gt;
Il effectue des calculs simultanés sur des plus petites listes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 7&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On souhaite trier une liste selon la hauteur des points c&#039;est-à-dire selon le deuxième élèment de la paire de flottants.&lt;br /&gt;
Pour cela, il faudrait faire un tri_fusion sur le 2eme élèment de la paire représentant les points&lt;br /&gt;
tout en sauvegardant le 1er élèment...&lt;br /&gt;
&lt;br /&gt;
 --- à venir ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Question 8 ( Bonus )&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 --- à venir ---&lt;/div&gt;</summary>
		<author><name>Caroline</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO421_:_Programmation_fonctionnelle&amp;diff=3889</id>
		<title>INFO421 : Programmation fonctionnelle</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO421_:_Programmation_fonctionnelle&amp;diff=3889"/>
		<updated>2009-03-04T09:07:13Z</updated>

		<summary type="html">&lt;p&gt;Caroline : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-401 : programmation fonctionnelle ». La participation au wiki est fortement encouragée, et deviendra peut-être obligatoire...&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Utilisez votre vrai nom...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller voir [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fôtes d&#039;aurtograffe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Détails techniques==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
Les nouvelles récentes sont en haut de la liste...&lt;br /&gt;
&lt;br /&gt;
* [[Utilisateur:Hyvernat|Hyvernat]] 9 février 2009 à 14:58 (CET) : &#039;&#039;&#039;le changement de jours pour le TP est confirmé : mercredi 11/02  à 13h30 en salle Maurienne 60.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Utilisateur:Hyvernat|Hyvernat]] 9 février 2009 à 10:57 (CET) : oups... La manifestation nationale est prévue pour mardi, et non pas mercredi comme je le pensais. Le TP sera probablement déplacé pour mercredi après-midi. (Je vous enverrais un email, et essaierais de venir vous voir en cours pour vous prévenir...)&lt;br /&gt;
&lt;br /&gt;
* [[Utilisateur:Hyvernat|Hyvernat]] 8 février 2009 à 15:59 (CET) : bien que je sois mobilisé contre les projets actuels du gouvernement, nous ferons la séance de TP prévue le mardi 10 février. (Sinon, ca sera compliqué à rattraper...) Je vous encourage à aller faire un peu de lecture [http://www.sauvonslarecherche.fr/ ici] (Sauvons la recherche) ou [http://www.lama.univ-savoie.fr/~mangolte/liens-greve.html là] (liens centralisés par F. Mangolte.&lt;br /&gt;
&lt;br /&gt;
* [[Utilisateur:Hyvernat|Hyvernat]] 8 février 2009 à 15:53 (CET) : comme je vous l&#039;avais annoncé, la séance de contrôle continu prévue dans Planète est supprimée : cette note sera remplacé par une note de participation aux corrections des TD/TP sur le wiki.&lt;br /&gt;
&lt;br /&gt;
* [[Utilisateur:Hyvernat|Hyvernat]] 22 janvier 2009 à 19:05 (CET) : la DSI a modifié des trucs qui devraient supprimer certains des problèmes qu&#039;on a eu en TP. Contactez-moi si vous rencontrez des problèmes en utilisant Emacs et Caml...&lt;br /&gt;
&lt;br /&gt;
* [[Utilisateur:Hyvernat|Hyvernat]] 22 janvier 2009 à 19:05 (CET) : j&#039;ai rajouté une page [[INFO401_corr_TD_TP | correction des TD / TP]].&lt;br /&gt;
&lt;br /&gt;
* [[Utilisateur:Hyvernat|Hyvernat]] 12 janvier 2009 à 09:59 (CET) : création du wiki.&lt;br /&gt;
&lt;br /&gt;
===Organisation des séances===&lt;br /&gt;
&lt;br /&gt;
* séance 1 (12/01/2009). Cours : introduction, programmation fonctionnelle, le langage Caml.&lt;br /&gt;
* séance 2 et 3 (19/01/2009).&lt;br /&gt;
*# Cours : les valeurs, les types atomiques et fonctionnels (section [[#Les_fonctions | Les fonctions]]).&lt;br /&gt;
*# TD1&lt;br /&gt;
* séance 4 (21/01/2009) : TP0 : prise en main de Caml.&lt;br /&gt;
* séance 5 et 6 (26/01/2009).&lt;br /&gt;
*# Cours : les tuples, les listes, un peu de filtrage et de polymorphisme&lt;br /&gt;
*# TD2 : tuples et listes, un peu de filtrage, questions 1.1, 1.2 et 1.4.&lt;br /&gt;
* séance 7 et 8 (26/12/2009) : suite du TD2.&lt;br /&gt;
&lt;br /&gt;
===Compléments de cours, TD et TP===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;&lt;br /&gt;
&amp;lt;center&amp;gt;&#039;&#039;&#039;&amp;lt;u&amp;gt;[[INFO401 corr TD TP | Corrections (partielles) des TD / TP]]&amp;lt;/u&amp;gt;&#039;&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Les travaux dirigés====&lt;br /&gt;
&lt;br /&gt;
* feuille de TD1 : [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/0809/info401/td1.pdf premières expressions en Caml]&lt;br /&gt;
&lt;br /&gt;
* feuille de TD2 : [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/0809/info401/td2.pdf tuples, listes, un peu de filtrage]&lt;br /&gt;
&lt;br /&gt;
====Les travaux pratiques====&lt;br /&gt;
&lt;br /&gt;
=====Ocaml=====&lt;br /&gt;
&lt;br /&gt;
Si vous voulez installer OCaml sur votre ordinateur.&lt;br /&gt;
&lt;br /&gt;
* Sous Linux : c&#039;est la solution idéale. Il existe probablement des paquets pour votre distribution. Pour Ubuntu, pour avoir un environnement similaire à ce que vous aurez dans les salles informatiques, installez les paquets &amp;lt;tt&amp;gt;ocaml&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;ocaml-core&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;ocaml-mode&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tuareg-mode&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;emacs&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Sous Windows : je vous renvoie au tutoriel de Jean-Paul Roy : [http://deptinfo.unice.fr/~roy/CAML/Win/install-win.html Installation de OCaml (sur Windows XP)]. Je n&#039;ai malheureusement (??) pas accès à une machine avec Windows (98/2000/XP/Vista/7), je ne pourrais donc pas beaucoup vous aider.&lt;br /&gt;
&lt;br /&gt;
Contactez moi si vous avez des problèmes.&lt;br /&gt;
&lt;br /&gt;
J&#039;ai créé une petite [http://www.lama.univ-savoie.fr/wiki/index.php?title=INFO401_:_utilisation_Caml page dédiée pour la syntaxe de Caml et son utilisation].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====TP0 : prise en main de Caml=====&lt;br /&gt;
&lt;br /&gt;
Le TP0 [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/0809/info401/tp0.pdf prise en main de Caml], au format pdf.&lt;br /&gt;
&lt;br /&gt;
* le petit fichier pour lancer l&#039;interprète Caml : [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/0809/info401/interprete-caml.desktop interprete-caml]. &amp;lt;small&amp;gt;(Pour le sauvegarder : clique droit sur le lien, &amp;quot;&amp;lt;tt&amp;gt;Enregistrer la cible du lien sous...&amp;lt;/tt&amp;gt;&amp;quot; ; mettez le sur le bureau, et ne modifiez pas le nom du fichier...)&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [http://caml.inria.fr/pub/docs/manual-ocaml-309/libref/Graphics.html la documentation de la librairie &amp;lt;tt&amp;gt;graphics&amp;lt;/tt&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====TP1 :  programmes récursifs, listes=====&lt;br /&gt;
&lt;br /&gt;
Le TP1 [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/0809/info401/tp1.pdf programmes récursifs, listes], au format pdf.&lt;br /&gt;
&lt;br /&gt;
* le [http://www.lama.univ-savoie.fr/~hyvernat/envoi-TP.php lien vers le formulaire d&#039;envoi du TP]&lt;br /&gt;
&lt;br /&gt;
* Une partie de [http://www.lama.univ-savoie.fr/wiki/index.php/INFO401_corr_TD_TP correction] du TP1...A compléter!&lt;br /&gt;
&lt;br /&gt;
====Références supplémentaires====&lt;br /&gt;
&lt;br /&gt;
* Le livre d&#039;Emmanuel Chailloux, Pascal Manoury et Bruno Pagano : [http://www.pps.jussieu.fr/Livres/ora/DA-OCAML/ Développement d&#039;applications avec Ocaml]. (Ce livre utilise une vieille version de Ocaml, mais reste pertinent.)&lt;br /&gt;
&lt;br /&gt;
* La documentation de Caml, version 3.09 (utilisé en TP) : [http://caml.inria.fr/pub/docs/manual-ocaml-309/ Documentation and user&#039;s manual].&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Pour paraphraser un collègue dont je ne retrouve pas le nom :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&#039;&#039;Attention :&#039;&#039; il ne s&#039;agit pas d&#039;un cours de programmation fonctionelle&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il s&#039;agit plutôt d&#039;un cours de programmation &#039;&#039;&#039;fonctio&amp;lt;u&amp;gt;nn&amp;lt;/u&amp;gt;elle&#039;&#039;&#039;...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Petit historique censuré===&lt;br /&gt;
&lt;br /&gt;
Je ne parlerais pas des langages pré-historiques (cartes perforées, λ-calcul, machines de Turing, ...)&lt;br /&gt;
&lt;br /&gt;
D&#039;après [http://people.ku.edu/~nkinners/LangList/Extras/langlist.htm ce site], qui recense la plupart des langages de programmation, il y aurait plus de 2500 langages ! Voici donc une petite liste de langages importants :&lt;br /&gt;
&lt;br /&gt;
* années 40 : langages d&#039;assemblage (assembleurs). Aussi vieux que les ordinateurs eux-mêmes. Chaque langage d&#039;assemblage est spécifique à une famille de processeurs, ce qui rend les programmes difficiles à &#039;&#039;porter&#039;&#039;. (Càd à modifier pour les faire marcher sur d&#039;autres ordinateurs.)&lt;br /&gt;
* FORTRAN (1957, toujours utilisé par les numériciens et physiciens) et COBOL (1960, toujours utilisé en gestion). Ces langages ont connus des évolutions mais restent archaïques par leur conception.&lt;br /&gt;
* LISP : inventé par John McCarthy en 1958. C&#039;est le premier langage fonctionnel. Toujours utilisé (sous différentes formes), en particulier en intelligence artificielle. Ce langage est basé directement sur le λ-calcul de Church.&lt;br /&gt;
* ALGOL (1958, a inspiré de nombreux langages depuis : C, pascal, ...) Le but était de réparer certains défauts des langages de type FORTRAN. (Programmation structurée, blocs, ...)&lt;br /&gt;
* Pascal (1975).&lt;br /&gt;
* C (1972). Toujours très utilisé, sous différentes variantes (notamment C++).&lt;br /&gt;
* Prolog (1972) : programmation logique, paradigme nouveau de programmation. Toujours utilisé par une petite communauté.&lt;br /&gt;
* ML (fin des années 1970 ?), qui ajoute une notion de type que LISP n&#039;avait pas.&lt;br /&gt;
* Smalltalk (fin des année 1983), début de la programmation objet.&lt;br /&gt;
* 1983 : ADA.&lt;br /&gt;
* 1983 : Miranda un langage fonctionnel « pur ».&lt;br /&gt;
* 1985 : Caml, développé à l&#039;INRIA.&lt;br /&gt;
* 1990 : Haskell, inspiré de Miranda.&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller voir le graphique suivant : [http://www.levenez.com/lang/lang.pdf Computer Languages Timeline] (ou [http://www.levenez.com/lang/redirect_lang_a4_pdf.html découpé en pages A4]).&lt;br /&gt;
&lt;br /&gt;
===Fonctionnel ??===&lt;br /&gt;
&lt;br /&gt;
L&#039;adjectif &#039;&#039;fonctionnel&#039;&#039; a au moins deux sens :&lt;br /&gt;
# qui fonctionne, en état de marche,&lt;br /&gt;
# qui se rapporte aux fonctions.&lt;br /&gt;
&lt;br /&gt;
Les langages fonctionnels sont bien entendus &#039;&#039;fonctionnels&#039;&#039; dans le premier sens, mais c&#039;est surtout le second sens qui nous intéresse.  Les langages tels que Pascal, Ada ou C sont qualifié, par opposition, d&#039;&#039;&#039;impératifs&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Un des slogans de la programmation fonctionnelle en général est &lt;br /&gt;
&amp;lt;center&amp;gt;&#039;&#039;&amp;lt;u&amp;gt;Les fonctions sont des valeurs comme les autres&amp;lt;/u&amp;gt;&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
et c&#039;est de là que vient la terminologie...&lt;br /&gt;
&lt;br /&gt;
Comme nous le verront, cela a de nombreuses conséquences sur l&#039;expressivité du langage et la manière de programmer.&lt;br /&gt;
&lt;br /&gt;
===Le langage (O)Caml===&lt;br /&gt;
&lt;br /&gt;
Le langage OCaml est développé par l&#039;INRIA (Institut national de recherche en informatique et automatique). C&#039;est un successeur de CamlLight.&lt;br /&gt;
&lt;br /&gt;
Le nom Caml est formé des initiales de &amp;quot;Categorical Abstract Machine Language&amp;quot;, et le langage lui même appartient à la famille de ML (&amp;quot;Meta Language&amp;quot;). C&#039;est un langage fonctionnel &#039;&#039;strict&#039;&#039; (nous verrons ce que cela veut dire), typé (nous verrons ce que cela veut dire) qui supporte plusieurs styles de programmation :&lt;br /&gt;
* fonctionnel bien sûr,&lt;br /&gt;
* mais aussi impératif,&lt;br /&gt;
* objet également (c&#039;est le « O » de OCaml).&lt;br /&gt;
&lt;br /&gt;
Dans ce cours, nous utiliserons seulement le style fonctionnel.&lt;br /&gt;
&lt;br /&gt;
Voici quelques aspects importants du langages que nous verrons peut-être pendant le cours :&lt;br /&gt;
* fonctions comme valeurs valeurs,&lt;br /&gt;
* polymorphisme,&lt;br /&gt;
* système d&#039;exceptions,&lt;br /&gt;
* système de modules et de foncteurs,&lt;br /&gt;
* support pour des références et des données mutables (programmation « impure »),&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Un aspect intéressant du langage est que c&#039;est soit :&lt;br /&gt;
* un langage interprété (avec l&#039;interpréteur OCaml),&lt;br /&gt;
* soit un langage compilé en bytecode (code binaire indépendant de l&#039;architecture),&lt;br /&gt;
* soit un langage compilé optimisé en binaire (dépendant de l&#039;architecture).&lt;br /&gt;
&lt;br /&gt;
On peut donc choisir ce que l&#039;on veut pour ces applications.&lt;br /&gt;
&lt;br /&gt;
===Autres langages fonctionnels===&lt;br /&gt;
&lt;br /&gt;
Il existe de nombreux autres langages fonctionnels. Je vous montrerais peut-être des exemples en cours. Voici quelques exemples importants :&lt;br /&gt;
* SML (Standard ML) : [http://en.wikipedia.org/wiki/Standard_ML Wikipedia], autre dialecte de la famille ML.&lt;br /&gt;
* LISP, dont les deux dialectes principaux sont :&lt;br /&gt;
&#039;&#039;&#039; Common LISP : [http://en.wikipedia.org/wiki/Common_LISP Wikipedia],&lt;br /&gt;
&#039;&#039;&#039; Scheme : [http://en.wikipedia.org/wiki/Scheme_(programming_language) Wikipedia].&lt;br /&gt;
* Haskell : [http://en.wikipedia.org/wiki/Haskell_(programming_language) Wikipedia] (inspiré en grande partie de [http://en.wikipedia.org/wiki/Miranda_(programming_language) Miranda]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Applications concrètes===&lt;br /&gt;
&lt;br /&gt;
Voici quelques exemples de logiciels développés en OCaml :&lt;br /&gt;
* [http://ocsigen.org/ Ocsigen], un serveur web,&lt;br /&gt;
* [http://www.cis.upenn.edu/~bcpierce/unison/ Unison], un logiciel de synchronisation de fichiers entre ordinateurs,&lt;br /&gt;
* [http://mldonkey.sourceforge.net/Main_Page MLDonkey], un logiciel de Peer-to-peer multiréseaux,&lt;br /&gt;
* [http://pauillac.inria.fr/advi/ Active DVI] un visualisateur pour le format de fichier DVI.&lt;br /&gt;
&lt;br /&gt;
La viabilité du paradigme fonctionnel se retrouve également dans le langage Erlang ([http://fr.wikipedia.org/wiki/Erlang_(langage) Wikipedia]), un langage fonctionnel développé par Ericsson pour la programmation concurrente de systèmes temps réels.&lt;br /&gt;
&lt;br /&gt;
D&#039;autre part, l&#039;efficacité des langages fonctionnels peut être constatée sur le [http://shootout.alioth.debian.org/ The Computer Language Benchmarks Game], où différents langages de programmation sont comparés (temps d&#039;exécution, taille du code source et utilisation de la mémoire) sur des taches différentes. Les langages fonctionnels sont toujours bien représentés...&lt;br /&gt;
&lt;br /&gt;
===Objectifs du cours===&lt;br /&gt;
&lt;br /&gt;
# être capable de définir des fonctions récursives, et comprendre ce qu&#039;elles font&lt;br /&gt;
# comprendre le typage et le polymorphisme à la ML&lt;br /&gt;
# pouvoir définir des fonction d&#039;ordre supérieur pour modulariser votre code&lt;br /&gt;
# être capable de décomposer un problème&lt;br /&gt;
# comprendre et utiliser la notion de type récursif&lt;br /&gt;
# commencer à réfléchir à la complexité de vos programmes&lt;br /&gt;
&lt;br /&gt;
==Premiers pas en Caml==&lt;br /&gt;
&lt;br /&gt;
===Les valeurs===&lt;br /&gt;
&lt;br /&gt;
Un des slogans de la programmation fonctionnelle est &#039;&#039;tout est une valeur, ou plus précisément,  &lt;br /&gt;
&amp;lt;center&amp;gt;&#039;&#039;Tout programme &amp;lt;u&amp;gt;a&amp;lt;/u&amp;gt; une valeur.&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette idée n&#039;est pas présente en C, et encore moins en Pascal, où l&#039;on distingue les &#039;&#039;expressions&#039;&#039; (&amp;quot;&amp;lt;tt&amp;gt;3*x+f(2)&amp;lt;/tt&amp;gt;&amp;quot; par exemple) et les &#039;&#039;instructions&#039;&#039; (&amp;quot;&amp;lt;tt&amp;gt;if (n&amp;gt;22) then a:=12 else a:=13&amp;lt;/tt&amp;gt;&amp;quot; par exemple). En Pascal, les instructions sont en général séparées par des &amp;quot;&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt;&amp;quot; et sont &#039;&#039;exécutées&#039;&#039; en séquence. Les expressions sont juste calculées, et ne peuvent pas être séquentialisées.&lt;br /&gt;
&lt;br /&gt;
Dans un langage purement fonctionnel, le &amp;quot;&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt;&amp;quot; n&#039;existe pas, et il n&#039;y a que des valeurs...&lt;br /&gt;
&lt;br /&gt;
Les valeurs sont formées en utilisant :&lt;br /&gt;
* les fonctions du langage (addition, multiplication)&lt;br /&gt;
* les opérateurs logiques (qui sont juste des fonctions des booléens vers les booléens),&lt;br /&gt;
* les relations mathématiques (égalité, plus grand, ... qui sont juste des fonctions dont le type de retour est le type des booléens),&lt;br /&gt;
* les constantes,&lt;br /&gt;
* les variables,&lt;br /&gt;
* des constructions du langage (&amp;lt;tt&amp;gt;if ... then ... else ...&amp;lt;/tt&amp;gt;) par exemple).&lt;br /&gt;
&lt;br /&gt;
Bien entendu, comme Caml est typé, il faut respecter les types.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Les valeurs de type atomique====&lt;br /&gt;
&lt;br /&gt;
Voici quelques exemples d&#039;expressions bien formées : on suppose que &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; est de type entier, &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; est de type flottant et &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt; de type chaîne de caractères.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 17&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 n&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 n+(3*2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 (n+3)*2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 n+3*2                  (* --&amp;gt; même valeur que  n+(3*2) *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 length (&amp;quot;Bonjour&amp;quot;)     (* --&amp;gt; valeur 7 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 length &amp;quot;Bonjour&amp;quot;       (* --&amp;gt; valeur 7 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 if (x&amp;gt;0) then n&lt;br /&gt;
          else (n+1)    (* --&amp;gt; suivant la valeur de x, c&#039;est soit la valeur de n, soit la valeur de n+1 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 (if (x&amp;gt;0) then n&lt;br /&gt;
           else n) + 1  (* --&amp;gt; (presque) la même chose que n+1 *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voici des exemples de valeurs mal formées :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 x+1                    (* --&amp;gt; x et 1 n&#039;ont pas le meme type *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 x+1.0                  (* --&amp;gt; le &amp;quot;+&amp;quot; ne fonctionne que sur des entiers (Pour les flottants, il faut utiliser &amp;quot;+.&amp;quot; &amp;quot;*.&amp;quot;, ...) *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 length x               (* --&amp;gt; length a un argument de type chaine, mais x est de type flottant *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 if (x=0) then x&lt;br /&gt;
          else n        (* --&amp;gt; le type d&#039;une valeur doit etre connu, mais x et n n&#039;ont pas le meme type *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 if (true) then x&lt;br /&gt;
           else n       (* --&amp;gt; idem (meme si dans ce cas, on peut ignorer le &amp;quot;else&amp;quot;) ()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Caml donne des messages d&#039;erreur explicites dans ces cas là. Par exemple, si on rentre l&#039;expression&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let x = 1.5 in x+1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Caml répond :&lt;br /&gt;
 # let x = 1.5 in &amp;lt;u&amp;gt;x&amp;lt;/u&amp;gt;+1 ;;&lt;br /&gt;
 This expression has type float but is here used with type int&lt;br /&gt;
(Remarquez le &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; souligné pour nous dire d&#039;où vient l&#039;erreur...)&lt;br /&gt;
&lt;br /&gt;
::&#039;&#039;&#039;Remarque :&#039;&#039;&#039; en Caml, on peut déclarer une variable locale à une expression avec la syntaxe &amp;quot;&amp;lt;tt&amp;gt;let x= expr in expr&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Les valeurs fonctionnelles====&lt;br /&gt;
&lt;br /&gt;
Les exemples du paragraphe précédent ne devraient pas trop vous surprendre. La vraie nouveauté est que même les fonctions sont des valeurs.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 length         (* valeur de type &amp;quot;fonction des chaînes vers les entiers&amp;quot; *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Une valeur de type fonctionnel peut être définie de la manière suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 fun x y -&amp;gt; 2*(x+y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ceci ressemble à une définition mathématique usuelle :&lt;br /&gt;
&amp;lt;center&amp;gt; La fonction qui à &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; et &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; associe &amp;lt;math&amp;gt;2\times(x+y)&amp;lt;/math&amp;gt;, que l&#039;on note habituellement &amp;lt;math&amp;gt;x,y\mapsto 2\times(x+y)&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remarquez que cette fonction n&#039;a pas de nom. Les langages impératifs tels que C, ou Pascal ne permettent pas de définir une fonction sans lui donner de nom.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une telle fonction avec 2 arguments pourra être appliquée pour obtenir une nouvelle valeur. Dans l&#039;exemple précédent, la fonction avaient deux arguments entiers et donnait un résultat de type entier. Si on donne le nom &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; à cette fonction :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let f = fun x y -&amp;gt; 2*(x+y)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
on pourra obtenir de nouvelles valeurs telles que :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 f 1 2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::&#039;&#039;&#039;Notez bien&#039;&#039;&#039; que pour appliquer une fonction à ses arguments, les parenthèses ne sont en général pas nécessaires, et qu&#039;on n&#039;utilise pas de &amp;quot;&amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt;&amp;quot; pour séparer les arguments.&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;environnement====&lt;br /&gt;
&lt;br /&gt;
Comme tous les langages de programmation, Caml garde en mémoire une liste de définitions. Chacune de ces définitions met en relation un nom (&amp;quot;&amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;&amp;quot;, &amp;quot;&amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt;&amp;quot;, &amp;quot;&amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt;&amp;quot;, ...) et une valeur (&amp;quot;&amp;lt;tt&amp;gt;3.7&amp;lt;/tt&amp;gt;&amp;quot;, &amp;quot;&amp;lt;tt&amp;gt;42&amp;lt;/tt&amp;gt;&amp;quot;, &amp;quot;&amp;lt;tt&amp;gt;fun s -&amp;gt; ...&amp;lt;/tt&amp;gt;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on lance Caml, l&#039;environnement contient déjà de nombreuse fonctions prédéfinies : &amp;lt;tt&amp;gt;max&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;min&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;mod&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;float_of_int&amp;lt;/tt&amp;gt;, ... Une occurrence d&#039;un nom de variable de l&#039;environnement qui est en position de &#039;&#039;variable libre&#039;&#039; sera remplacé par la valeur correspondante.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Définitions=====&lt;br /&gt;
&lt;br /&gt;
L&#039;utilisateur peut rajouter des définitions dans l&#039;environnement grâce au mot clé &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;let &#039;&#039;nom&#039;&#039; = &#039;&#039;expr&#039;&#039;&amp;lt;/tt&amp;gt; permet de rajouter une définition simple dans l&#039;environnement. Exemple : &amp;lt;tt&amp;gt;let n = 42&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;let &#039;&#039;nom1&#039;&#039; = &#039;&#039;expr1&#039;&#039; and &#039;&#039;nom2&#039;&#039; = &#039;&#039;expr2&#039;&#039;&amp;lt;/tt&amp;gt; permet de rajouter plusieurs définitions simultanément. Exemple : &amp;lt;tt&amp;gt;let a=1 and b=2&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;let rec &#039;&#039;nom&#039;&#039; = &#039;&#039;expr&#039;&#039;&amp;lt;/tt&amp;gt; permet de rajouter une définition récursive dans l&#039;environnement. Exemple : &amp;lt;tt&amp;gt;let rec f n = if (n&amp;lt;1) then 0 else n+ f (n-1)&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;let rec &#039;&#039;nom1&#039;&#039; = &#039;&#039;expr1&#039;&#039; and &#039;&#039;nom2&#039;&#039; = &#039;&#039;expr2&#039;&#039;&amp;lt;/tt&amp;gt; permet de rajouter des définitions mutuellement récursives.&lt;br /&gt;
&lt;br /&gt;
Dans chacun des cas précédents, on peut annoter la définition de types de données. Ceci évite à Caml d&#039;avoir à deviner le type que l&#039;on souhaite et permet de préciser la fonction :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let n:int = 42&lt;br /&gt;
 let rec f (n:int) : string = if (n&amp;lt;1) then &amp;quot;&amp;quot; else &amp;quot;*&amp;quot; ^ (f (n-1))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Si une définition utilise le même nom qu&#039;une définition précédente, la nouvelle définition écrase l&#039;ancienne. Par exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # let n=42 ;;&lt;br /&gt;
 val n : int = 42&lt;br /&gt;
 # let n=3.1415 ;;&lt;br /&gt;
 val n : float = 3.1415&lt;br /&gt;
 # n ;;&lt;br /&gt;
 - : float = 3.1415&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Définitions locales=====&lt;br /&gt;
&lt;br /&gt;
Il est possible de modifier l&#039;environnement de manière temporaire (&#039;&#039;locale&#039;&#039;). On utilise alors &amp;lt;tt&amp;gt;let &#039;&#039;nom&#039;&#039; = &#039;&#039;expr1&#039;&#039; in &#039;&#039;expr2&#039;&#039;&amp;lt;/tt&amp;gt;. Ceci ajoute la définition &amp;lt;tt&amp;gt;&#039;&#039;nom&#039;&#039; = &#039;&#039;expr1&#039;&#039;&amp;lt;/tt&amp;gt; dans l&#039;environnement, mais seulement pour l&#039;évaluation de l&#039;expression &amp;lt;tt&amp;gt;&#039;&#039;expr2&#039;&#039;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let x =&lt;br /&gt;
  let y = 42 in&lt;br /&gt;
    y/2 ;;&lt;br /&gt;
val x : int = 21&lt;br /&gt;
# x ;;&lt;br /&gt;
- : int = 21&lt;br /&gt;
# y ;;&lt;br /&gt;
Unbound value y&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les définitions locales peuvent elles aussi être multiples (&amp;lt;tt&amp;gt;let ... and ... in&amp;lt;/tt&amp;gt;), récursives (&amp;lt;tt&amp;gt;let rec ... in&amp;lt;/tt&amp;gt;), mutuellement récursives (&amp;lt;tt&amp;gt;let rec ... and ... in&amp;lt;/tt&amp;gt;). Elles acceptent également les annotations de type...&lt;br /&gt;
&lt;br /&gt;
====Transparence référentielle====&lt;br /&gt;
&lt;br /&gt;
Une des idées importantes en programmation fonctionnelle est la notion de « transparence référentielle » : grosso-modo, cela veut dire que l&#039;on a toujours le droit de remplacer une expression par sa valeur sans changer le sens du programme. Bien que ceci semble évident, ce n&#039;est pas vrai dans un langage tels que le langage C...&lt;br /&gt;
&lt;br /&gt;
Pour comprendre pourquoi ceci n&#039;est pas vrai dans un programme Pascal, considérez la fonction suivante&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
 function f (x:integer) : integer ;&lt;br /&gt;
 begin&lt;br /&gt;
   writeln(&#039;Salut...&#039;);&lt;br /&gt;
   y:=0;                    { y est une variable globale }&lt;br /&gt;
   f:=x+1;&lt;br /&gt;
 end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
La valeur de &amp;lt;tt&amp;gt;f(3)&amp;lt;/tt&amp;gt; est &amp;lt;tt&amp;gt;4&amp;lt;/tt&amp;gt;, mais on ne peut pas remplacer &amp;lt;tt&amp;gt;f(3)&amp;lt;/tt&amp;gt; par &amp;lt;tt&amp;gt;4&amp;lt;/tt&amp;gt; sans changer le comportement du programme...&lt;br /&gt;
&lt;br /&gt;
C&#039;est cette propriété qui facilite grandement la formalisation des langages fonctionnels, car on peut appliquer le principe mathématique&lt;br /&gt;
&amp;lt;center&amp;gt; si &amp;lt;math&amp;gt;x=y&amp;lt;/math&amp;gt; alors &amp;lt;math&amp;gt;f(x)=f(y)&amp;lt;/math&amp;gt;.&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Les types===&lt;br /&gt;
&lt;br /&gt;
====Les types atomiques====&lt;br /&gt;
&lt;br /&gt;
Caml (et les autres langages fonctionnels typés) possèdent plusieurs types de base tels que :&lt;br /&gt;
* les booléens : type &amp;lt;tt&amp;gt;bool&amp;lt;/tt&amp;gt; (valeur &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;),&lt;br /&gt;
* les entiers : type &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; pour les entiers signés compris entre &amp;lt;math&amp;gt;-2^{30}&amp;lt;/math&amp;gt; et &amp;lt;math&amp;gt;2^{30}-1&amp;lt;/math&amp;gt;. (Les entiers Caml sont stockés sur 31 bits...)&lt;br /&gt;
* les flottants : type &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; pour les réels en virgule flottante,&lt;br /&gt;
* les caractères : type &amp;lt;tt&amp;gt;char&amp;lt;/tt&amp;gt; (notés entre guillemets simples)&lt;br /&gt;
* le type unité : type &amp;lt;tt&amp;gt;unit&amp;lt;/tt&amp;gt;, dont l&#039;unique valeur est &amp;lt;tt&amp;gt;()&amp;lt;/tt&amp;gt;. (Nous verrons que ce type a une utilité...)&lt;br /&gt;
&lt;br /&gt;
Même s&#039;il ne s&#039;agit pas vraiment d&#039;un type atomique, nous pouvons également ajouter le type des chaînes de caractères : type &amp;lt;tt&amp;gt;string&amp;lt;/tt&amp;gt; (notées entre guillemets doubles).&lt;br /&gt;
&lt;br /&gt;
Caml définit de nombreuse fonctions sur ces types de données :&lt;br /&gt;
* opérations arithmétiques&lt;br /&gt;
* fonctions mathématiques usuelles (logarithme, sinus, ...)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
::&#039;&#039;&#039;Remarques :&#039;&#039;&#039; les opérations booléennes (&amp;quot;&amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt;&amp;quot; pour le « et » et &amp;quot;&amp;lt;tt&amp;gt;||&amp;lt;/tt&amp;gt;&amp;quot; pour le « ou ») fonctionnent de à gauche à droite, et l&#039;argument de droite n&#039;est évalué que si c&#039;est nécessaires. Par exemple &amp;lt;tt&amp;gt;true || (0 = 1/0)&amp;lt;/tt&amp;gt; donne la valeur &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;, alors que que &amp;lt;tt&amp;gt;false || (0=1/0)&amp;lt;/tt&amp;gt; lève l&#039;exception &amp;lt;tt&amp;gt;Division_by_zero&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Les fonctions====&lt;br /&gt;
&lt;br /&gt;
Caml utilise la notation mathématique pour écrire les types des fonctions. Si &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; est une fonction avec un seul argument de type &amp;lt;tt&amp;gt;string&amp;lt;/tt&amp;gt; et d&lt;br /&gt;
ont la valeur de retour est de type &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; (la fonction &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; par exemple), le type de &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; est noté &amp;lt;tt&amp;gt;string -&amp;gt; int&amp;lt;/tt&amp;gt;. Dans l&#039;in&lt;br /&gt;
terprète Caml :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # length ;;&lt;br /&gt;
 - : string -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Nous indique que la fonction &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; est bien de type &amp;lt;tt&amp;gt;string-&amp;gt;int&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Une nouveauté des langages fonctionnels par rapports à Pascal est que &amp;lt;tt&amp;gt;string-&amp;gt;int&amp;lt;/tt&amp;gt; est un type comme les autre, et on peut donc créer une fonction d&lt;br /&gt;
e type &amp;lt;tt&amp;gt;string -&amp;gt; (string -&amp;gt; int)&amp;lt;/tt&amp;gt;. Prenons par exemple la fonction suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let f:string-&amp;gt;int = fun s -&amp;gt;&lt;br /&gt;
                       let t = &amp;quot;prefix-&amp;quot; in&lt;br /&gt;
                       length (t ^ s)      (* &amp;quot;^&amp;quot; est l&#039;opérateur de concaténation des chaînes. *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Cette fonction va calculer la longueur de son argument, auquel on a rajouter le préfixe &amp;lt;tt&amp;gt;&amp;quot;prefix-&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Si on veut pouvoir changer le préfixe que l&#039;on rajoute devant &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;, on peut faire la fonction suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let g:string -&amp;gt; ( string -&amp;gt; int) =&lt;br /&gt;
   fun prefix -&amp;gt;&lt;br /&gt;
     fun s -&amp;gt; length (t^s)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; précédente aurait pu être obtenue grâce à &amp;quot;&amp;lt;tt&amp;gt;g &amp;quot;prefix-&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::&#039;&#039;&#039;Remarque :&#039;&#039;&#039; Caml n&#039;utilise pas les parenthèses dans ce cas là : il notera &amp;quot;&amp;lt;tt&amp;gt;string -&amp;gt; string -&amp;gt; int&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous verrons un peu plus tard que les fonctions peuvent avoir des arguments qui sont eux mêmes des fonctions.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; essayez de trouver une fonction de type &amp;lt;tt&amp;gt;(int-&amp;gt;int) -&amp;gt; int&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Les paires====&lt;br /&gt;
&lt;br /&gt;
Un autre type intéressant est celui des paires de valeur. Par exemple, le type &amp;quot;&amp;lt;tt&amp;gt;int * string&amp;lt;/tt&amp;gt;&amp;quot; est compose de valeur &amp;quot;&amp;lt;tt&amp;gt;(3,&amp;quot;toto&amp;quot;)&amp;lt;/tt&amp;gt;&amp;quot;. On peut accéder au premier élément d&#039;une paire avec la fonction &amp;quot;&amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;&amp;quot; et au second élément avec la fonction &amp;quot;&amp;lt;tt&amp;gt;snd&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let paire = (&amp;quot;Bonjour !&amp;quot; , 42*42) in (snd paire)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
donnera la valeur 1764.&lt;br /&gt;
&lt;br /&gt;
Ce type correspond exactement à la notion de &#039;&#039;produit cartésien&#039;&#039; utilisée en mathématiques :&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; A \times B \quad=\quad \{ (a,b) \ |\ a\in A \,,\,b\in B\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les fonctions &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;snd&amp;lt;/tt&amp;gt; sont généralement appelées &#039;&#039;projections&#039;&#039; :&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; \pi_1 : A\times B \to A \qquad (a,b) \mapsto a&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
(et pareillement pour la projection sur l&#039;élément de droite...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ce type de données particulièrement utile lorsque l&#039;on veut écrire une fonction qui renvoie 2 ou 3 valeurs. On verra par la suite qu&#039;il existe d&#039;autre types plus appropriés si l&#039;on veut avoir de nombreux champs, et s&#039;il l&#039;on veut leur donner un nom. (Dans une paire, la première composante et la seconde composante n&#039;ont pas de nom propre...)&lt;br /&gt;
&lt;br /&gt;
Notez également que les fonctions a plusieurs arguments n&#039;utilisent en général pas de produit cartésien. Pour Caml :&lt;br /&gt;
* une fonction de type &amp;lt;tt&amp;gt;(A*B) -&amp;gt; C&amp;lt;/tt&amp;gt; est une fonction à un seul argument, mais son argument est une paire,&lt;br /&gt;
* une fonction de type &amp;lt;tt&amp;gt;A -&amp;gt; B -&amp;gt; C&amp;lt;/tt&amp;gt; est une fonction à deux arguments séparés. (Plus précisément, c&#039;est une fonction à un argument qui renvoie une fonction à un argument.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;Exercice : &amp;lt;/u&amp;gt; cherchez une manière de passer d&#039;une fonction de type &amp;lt;tt&amp;gt;A*B -&amp;gt; C&amp;lt;/tt&amp;gt; à une fonction de type &amp;lt;tt&amp;gt;A -&amp;gt; B -&amp;gt; C&amp;lt;/tt&amp;gt;, et vice-versa. Ces transformations s&#039;appellent la &#039;&#039;curryfication&#039;&#039; et la &#039;&#039;decurryfication&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
:Écrivez les fonctions &amp;lt;tt&amp;gt;curry :: (&#039;a*&#039;b -&amp;gt; &#039;c) -&amp;gt; (&#039;a -&amp;gt; &#039;b -&amp;gt; &#039;c)&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;un curry : (&#039;a -&amp;gt; &#039;b -&amp;gt; &#039;c) -&amp;gt; (&#039;a*&#039;b -&amp;gt; &#039;c)&amp;lt;/tt&amp;gt; en Caml.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans de nombreux cas, les parenthèses autour d&#039;un tuple ne sont pas nécessaires :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let x = 42 , &amp;quot;Toto&amp;quot; and y = (42 , &amp;quot;Toto&amp;quot;) in&lt;br /&gt;
    x=y ;;&lt;br /&gt;
- : bool = true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Dans le doute, mettez des parenthèses pour éviter des bugs.&lt;br /&gt;
&lt;br /&gt;
====Les listes====&lt;br /&gt;
&lt;br /&gt;
Le type des listes est fondamental en programmation fonctionnelle. D&#039;une certaine manière, on peut dire qu&#039;ils remplacent les tableaux que l&#039;on utilise constamment en programmation impérative.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;Exercice : &amp;lt;/u&amp;gt; quels sont les différences importantes (utilisation, complexité, mémoire, ...) entre les tableaux et les listes ?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En Caml, une liste est représentée entre crochets, et les éléments sont séparés par des points-virgules :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # let une_liste = [ 1 ; 2 ; 2 ; -1 ; 0 ] ;;&lt;br /&gt;
 val une_liste : int list = [1; 2; 2; -1; 0]&lt;br /&gt;
 # let une_autre_liste = [ &amp;quot;coucou&amp;quot; ; &amp;quot;je m&#039;appelle&amp;quot; ; &amp;quot;Bob&amp;quot; ] ;;&lt;br /&gt;
 val une_autre_liste : string list = [&amp;quot;coucou&amp;quot;; &amp;quot;je m&#039;appelle&amp;quot;; &amp;quot;Bob&amp;quot;]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme vous pouvez le voir dans l&#039;exemple au dessus, le type des listes d&#039;entiers s&#039;appelle &amp;quot;&amp;lt;tt&amp;gt;int list&amp;lt;/tt&amp;gt;&amp;quot;, le type des listes de flottants s&#039;appelle &amp;quot;&amp;lt;tt&amp;gt;float list&amp;lt;/tt&amp;gt;&amp;quot; et le type des listes de listes d&#039;entiers s&#039;appelle ... &amp;quot;&amp;lt;tt&amp;gt;int list list&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Contrairement au cas du produit cartésien de types, les éléments d&#039;une liste doivent tous avoir le même type :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # let une_non_liste = [ 1 ; &amp;quot;Toto&amp;quot; ; 1.3 ] ;;&lt;br /&gt;
 This expression has type string but is here used with type int&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Attention : &#039;&#039;&#039; quel est le type de la liste suivante ?&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # let une_liste_bizarre = [ 1 , 2 , 3 ] ;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La concaténation des listes s&#039;obtient avec l&#039;opérateur &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot; et pour rajouter un element devant une liste existante on utilise &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# 0::[1;2;3;4] ;;&lt;br /&gt;
- : int list = [0; 1; 2; 3; 4]&lt;br /&gt;
# [-1;-2;-3;-4] @ [1;2;3;4] ;;&lt;br /&gt;
- : int list = [-1; -2; -3; -4; 1; 2; 3; 4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Il existe en plus (dans la bibliothèque &amp;quot;&amp;lt;tt&amp;gt;List&amp;lt;/tt&amp;gt;&amp;quot; les fonctions suivantes&lt;br /&gt;
* &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* &amp;lt;tt&amp;gt;hd&amp;lt;/tt&amp;gt; pour récupérer le premier élément d&#039;une liste,&lt;br /&gt;
* &amp;lt;tt&amp;gt;tl&amp;lt;/tt&amp;gt; pour récupérer la &#039;&#039;queue&#039;&#039; d&#039;une liste (toute la liste, sans son premier élément).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; Caml possède plusieurs fonctions &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt; : notamment une pour les listes et une pour les chaînes de caractères. Pour accéder à ces fonctions (qui ne sont pas dans la bibliothèque standard), il faut utiliser :&lt;br /&gt;
:* &amp;lt;tt&amp;gt;List.length&amp;lt;/tt&amp;gt; pour la longueur des listes,&lt;br /&gt;
:* &amp;lt;tt&amp;gt;String.length&amp;lt;/tt&amp;gt; pour la longueur des chaînes.&lt;br /&gt;
:Vous pouvez aussi &#039;&#039;ouvrir&#039;&#039; toute la bibliothèque correspondante en utilisant la ligne &amp;quot;&amp;lt;tt&amp;gt;open List&amp;lt;/tt&amp;gt;&amp;quot; au début de votre programme pour avoir accès à toutes les fonctions de la bibliothèque sur les listes...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La manière usuelle de définir des fonctions récursives sur les listes d&#039;utilisez plutôt le &#039;&#039;filtrage&#039;&#039; (&#039;&#039;&amp;quot;pattern matching&amp;quot;&#039;&#039;) décrit plus loin, ou les fonctions prédéfinies comme &amp;lt;tt&amp;gt;List.fold_left&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;List.fold_right&amp;lt;/tt&amp;gt; (qui seront vues en TD et TP).&lt;br /&gt;
&lt;br /&gt;
 --- examples et explication de fold ?&lt;br /&gt;
&lt;br /&gt;
====Filtrage, première partie====&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;filtrage&#039;&#039;, aussi appelé &#039;&#039;&amp;quot;pattern-matching&amp;quot;&#039;&#039; est un outils clé pour la programmation en Caml. L&#039;idée est d&#039;essayer de faire correspondre une valeur avec un certain nombre de &#039;&#039;motifs&#039;&#039;. Le &amp;quot;&amp;lt;tt&amp;gt;case .. of&amp;lt;/tt&amp;gt;&amp;quot; de Pascal en est une version ultra pauvre et simplifiée.&lt;br /&gt;
&lt;br /&gt;
En Caml, la syntaxe du pattern matching est la suivante : &lt;br /&gt;
 match &#039;&#039;expr&#039;&#039; with&lt;br /&gt;
    &#039;&#039;pattern1&#039;&#039;  -&amp;gt;  &#039;&#039;expr1&#039;&#039;&lt;br /&gt;
  | &#039;&#039;pattern2&#039;&#039;  -&amp;gt;  &#039;&#039;expr2&#039;&#039;&lt;br /&gt;
  | &#039;&#039;pattern3&#039;&#039;  -&amp;gt;  &#039;&#039;expr3&#039;&#039;&lt;br /&gt;
  | &#039;&#039;pattern4&#039;&#039;  -&amp;gt;  &#039;&#039;expr4&#039;&#039;&lt;br /&gt;
L&#039;évaluation d&#039;une telle expression se fait de la manière suivante : Caml évalue l&#039;expression &amp;quot;&#039;&#039;&amp;lt;tt&amp;gt;expr&amp;lt;/tt&amp;gt;&#039;&#039;&amp;quot;, et essaie de la faire coïncider au motif &amp;quot;&amp;lt;tt&amp;gt;pattern1&amp;lt;/tt&amp;gt;&amp;quot; (on dit que Caml essaie d&#039;&amp;lt;i&amp;gt;unifier&amp;lt;/i&amp;gt; l&#039;expression &amp;quot;&#039;&#039;&amp;lt;tt&amp;gt;expr&amp;lt;/tt&amp;gt;&#039;&#039;&amp;quot; avec le motif &amp;quot;&#039;&#039;&amp;lt;tt&amp;gt;pattern1&amp;lt;/tt&amp;gt;&#039;&#039;&amp;quot;). Si il y parvient, il évalue l&#039;expression &amp;quot;&#039;&#039;&amp;lt;tt&amp;gt;expr1&amp;lt;/tt&amp;gt;&#039;&#039;&amp;quot; et renvoie la valeur correspondante. Caml regarde tous les motif dans l&#039;ordre.&lt;br /&gt;
&lt;br /&gt;
Par exemple,&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 match (2+2) with&lt;br /&gt;
    1 -&amp;gt; &amp;quot;Problème.&amp;quot;&lt;br /&gt;
 |  3 -&amp;gt; &amp;quot;Problème.&amp;quot;&lt;br /&gt;
 |  4 -&amp;gt; &amp;quot;Ouf&amp;quot;&lt;br /&gt;
 |  _ -&amp;gt; &amp;quot;problème.&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
s&#039;évaluera en la valeur &amp;lt;tt&amp;gt;&amp;quot;Ouf&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le motif &amp;quot;&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;&amp;quot; est un motif &#039;&#039;universel&#039;&#039;, et permet de faire ce que l&#039;on ferait avec un &amp;quot;&amp;lt;tt&amp;gt;else&amp;lt;/tt&amp;gt;&amp;quot; en Pascal. Le véritable avantage de filtrage de Caml se voit dans le filtrage sur les types &#039;&#039;&amp;quot;composés&amp;quot;&#039;&#039; comme les tuples, les listes ou les types sommes. Le filtrage permet de &amp;quot;déconstruire&amp;quot; une valeur en ces différents constituants. Par exemple, voici comment on pourrait programmer la fonction &amp;quot;&amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let premier p = match p with&lt;br /&gt;
    (x,y) -&amp;gt; x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Pour évaluer &amp;quot;&amp;lt;tt&amp;gt;premier e&amp;lt;/tt&amp;gt;&amp;quot;, Caml essaie de faire coïncider la valeur de &amp;quot;&amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt;&amp;quot; avec un truc de la forme &amp;quot;&amp;lt;tt&amp;gt;(x,y)&amp;lt;/tt&amp;gt;&amp;quot;. S&#039;il y arrive, alors il renvoie la valeur &amp;quot;&amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;&amp;quot;. Le typage de Caml inférera automatique que &amp;quot;&amp;lt;tt&amp;gt;p&amp;lt;/tt&amp;gt;&amp;quot; doit être une paire, et il n&#039;y a donc pas besoin de prévoir un cas par defaut.&lt;br /&gt;
&lt;br /&gt;
On peut écrire des motifs plus intéressants comme&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let imaginaire_pur x = match x with&lt;br /&gt;
    (0,_) -&amp;gt; true&lt;br /&gt;
  | _  -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
qui permettra de tester si la première coordonnée (partie réelle d&#039;une nombre complexe) est nulle ou pas. On aura pu écrire de manière équivalente :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let imaginaire_pur x = if (fst x = 0) then true else false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;u&amp;gt; Question :&amp;lt;/u&amp;gt; à votre avis, que fait la fonction suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let une_fonction x = match x with&lt;br /&gt;
    (1,(y,z))  -&amp;gt; y-z&lt;br /&gt;
  | (0,(y,z)   -&amp;gt; y+z&lt;br /&gt;
  | (-1,(y,z)  -&amp;gt; z-y&lt;br /&gt;
  | (_,(y,_)   -&amp;gt; y&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Attention :&#039;&#039;&#039; les variables qui apparaissent dans les motifs « écrasent » les variables de même nom qui peuvent apparaître avant dans l&#039;expression :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let f x = match x with&lt;br /&gt;
 (x,_) -&amp;gt; x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:calcule la fonction &amp;quot;&amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;&amp;quot;. De plus, les motifs ne sont pas évalués : dans&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let un = 1&lt;br /&gt;
 let g x = match x with&lt;br /&gt;
     un -&amp;gt; 1&lt;br /&gt;
   | 2 -&amp;gt; 2&lt;br /&gt;
   | _ -&amp;gt; 3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:la fonction &amp;quot;&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;&amp;quot; prendra toujours la valeur &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; car le &amp;quot;&amp;lt;tt&amp;gt;un&amp;lt;/tt&amp;gt;&amp;quot; est considéré comme un nom de variable...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pour filtrer sur une liste, on utilise &amp;quot;&amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt;&amp;quot; et &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot;. Par exemple, voici une manière de tester si une liste est vide :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let vide l = match l with&lt;br /&gt;
     [] -&amp;gt; true&lt;br /&gt;
   | x::xs  -&amp;gt;  false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
On peut écrire des fonctions comme&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let un_element l = match l with&lt;br /&gt;
    [x] -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
let deux_elements l = match l with&lt;br /&gt;
    x::y::[] -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
let trois_element_ou_plus l = match l with&lt;br /&gt;
    _::_::_::_  -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 --- complément sur l&#039;unification, un peu plus de détails ?&lt;br /&gt;
 --- un motif qui contient juste une variable est universel&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Compléments syntaxiques :&#039;&#039;&#039; Caml définit les sucres syntaxiques suivants&lt;br /&gt;
:* &amp;quot;or pattern&amp;quot; : on peut grouper plusieurs motifs qui définissent les mêmes variables et donnent la même expression&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let f x = match x with&lt;br /&gt;
    0::l | 1::l | 1::l  -&amp;gt; l  (* on groupe 3 motifs en une seule ligne *)&lt;br /&gt;
  | [] -&amp;gt; []&lt;br /&gt;
  | x::_ -&amp;gt; [x]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:* &amp;quot;garde pour les motifs&amp;quot; : on peut « garder » les motifs par une condition avec le mot clé &amp;quot;&amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let g x = match x with&lt;br /&gt;
    x::xs  when (List.lenght (f xs) = 1)  -&amp;gt;  true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:* fonction par filtrage : comme on définit souvent des fonctions par filtrage, Caml autorise la syntaxe&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
function&lt;br /&gt;
    pattern1 -&amp;gt; expr1&lt;br /&gt;
  | pattern2 -&amp;gt; expr2&lt;br /&gt;
  | ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:plutôt que&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
fun x -&amp;gt; match x with&lt;br /&gt;
    pattern1 -&amp;gt; expr1&lt;br /&gt;
  | pattern2 -&amp;gt; expr2&lt;br /&gt;
  | ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Remarquez que l&#039;on ne peut faire ça que pour une fonction à une seule variable...&lt;br /&gt;
:* fonction par filtrage : s&#039;il n&#039;y a qu&#039;un seul motif, on peut alors utiliser le mot clé &amp;quot;&amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt;&amp;quot; habituel, ce qui permet la définition d&#039;une fonction à plusieurs arguments. (Mais dans ce cas, les parenthèses autour des tuples sont obligatoires.)&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let h = fun (x,y) z (u,v,w)  -&amp;gt;  x+y+z+v ;;&lt;br /&gt;
val h : int * int -&amp;gt; int -&amp;gt; &#039;a * int * &#039;b -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Le polymorphisme====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que Caml était un langage fortement typé : toutes les expressions ont un type, et on ne peut appliquer des fonctions que lorsqu&#039;elles ont ses arguments ont le bon type.&lt;br /&gt;
&lt;br /&gt;
Quel est le type de la fonction &amp;quot;&amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;&amp;quot; ?&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let fst = function (x,_) -&amp;gt; x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Cette fonction est à la fois de type &amp;quot;&amp;lt;tt&amp;gt;int * int -&amp;gt; int&amp;lt;/tt&amp;gt;&amp;quot;, &amp;quot;&amp;lt;tt&amp;gt;int * float -&amp;gt; int&amp;lt;/tt&amp;gt;&amp;quot;, ... Pour Caml, cette fonction est de type &amp;quot;&amp;lt;tt&amp;gt;t1 * t2 -&amp;gt; t1&amp;lt;/tt&amp;gt;&amp;quot; pour n&#039;importe quels types &amp;quot;&amp;lt;tt&amp;gt;t1&amp;lt;/tt&amp;gt;&amp;quot; et &amp;quot;&amp;lt;tt&amp;gt;t2&amp;lt;/tt&amp;gt;&amp;quot;. Caml dénote un tel type avec de guillemets simples de la manière suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let fst = function (x,_) -&amp;gt; x ;;&lt;br /&gt;
val fst : &#039;a * &#039;b -&amp;gt; &#039;a = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;Complément : &#039;&#039; même si cela ne vous arrivera probablement pas dans un premier temps, sachez que seuls les valeurs &#039;&#039;évaluées&#039;&#039; peuvent être polymorphes. Par exemple, dans&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let i x = x&lt;br /&gt;
  let j = i i ;;&lt;br /&gt;
val i : &#039;a -&amp;gt; &#039;a = &amp;lt;fun&amp;gt;&lt;br /&gt;
val j : &#039;_a -&amp;gt; &#039;_a = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:l&#039;expression &amp;quot;&amp;lt;tt&amp;gt;j&amp;lt;/tt&amp;gt;&amp;quot; n&#039;est pas vraiment polymorphe. (C&#039;est le sens du &amp;quot;&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;&amp;quot; devant le &amp;quot;&amp;lt;tt&amp;gt;a&amp;lt;/tt&amp;gt;&amp;quot;.) Le &amp;quot;&amp;lt;tt&amp;gt;&#039;_a&amp;lt;/tt&amp;gt;&amp;quot; veut dire : « &#039;&#039;la fonction &amp;quot;&amp;lt;tt&amp;gt;j&amp;lt;/tt&amp;gt;&amp;quot; a pour type &amp;quot;&amp;lt;tt&amp;gt;t -&amp;gt; t&amp;lt;/tt&amp;gt;&amp;quot;, mais je ne connais pas encore ce type &amp;quot;&amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;&amp;quot;.)&#039;&#039; »&lt;br /&gt;
:Dés que l&#039;on applique &amp;quot;&amp;lt;tt&amp;gt;j&amp;lt;/tt&amp;gt;&amp;quot; à quelque chose, Caml pourra savoir quel est le type de &amp;quot;&amp;lt;tt&amp;gt;j&amp;lt;/tt&amp;gt;&amp;quot; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# j 42 ;;&lt;br /&gt;
- : int = 42&lt;br /&gt;
# j ;;&lt;br /&gt;
- : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; polymorphisme « ad-hoc »...&lt;br /&gt;
 --- à faire&lt;br /&gt;
&lt;br /&gt;
==Les types avec constructeurs (types &#039;&#039;sommes&#039;&#039;)==&lt;br /&gt;
&lt;br /&gt;
Nous avons vu en TP qu&#039;il était possible de définir un &#039;&#039;synonyme de type&#039;&#039; avec le mot clé &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; : par exemple&lt;br /&gt;
&amp;lt;code lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type point = float * float&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
permet de définir un nouveau type appelé &amp;quot;&amp;lt;tt&amp;gt;point&amp;lt;/tt&amp;gt;&amp;quot;. Les valeurs de ce type sont exactement les même que celle de type &amp;quot;&amp;lt;tt&amp;gt;float*float&amp;lt;/tt&amp;gt;&amp;quot;. C&#039;est bien, mais ça ne permet de définir de &#039;&#039;nouveaux&#039;&#039; types.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Déclaration des types sommes===&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;type avec constructeur&#039;&#039; est centrale dans les langage fonctionnelle de la famille ML ou Miranda. Ces types vont pouvoir par exemple servir à définir des types finis :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type jours = Lundi | Mardi | Mercredi | Jeudi | Vendredi | Samedi | Dimanche&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour déclarer un type avec constructeur, on utilise &amp;quot;&amp;lt;tt&amp;gt;type &#039;&#039;nom_type&#039;&#039; = &#039;&#039;Constr_1&#039;&#039; | ... | &#039;&#039;Constr_n&#039;&#039;&amp;lt;/tt&amp;gt;&amp;quot; où :&lt;br /&gt;
* &amp;lt;tt&amp;gt;&#039;&#039;nom_type&#039;&#039;&amp;lt;/tt&amp;gt; est le nom du type que l&#039;on définit. Ce nom doit forcement commencer par une minuscule. (Comme les types prédéfinis : &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt;, ...)&lt;br /&gt;
* &amp;lt;tt&amp;gt;&#039;&#039;Constr_1&#039;&#039;&amp;lt;/tt&amp;gt; et suivants sont les &#039;&#039;constructeurs&#039;&#039; du type. Même si ce n&#039;est pas obligatoire, les constructeurs commencent souvent par une majuscule.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les types avec constructeurs deviennent plus intéressant lorsque l&#039;on rajoute des &#039;&#039;arguments&#039;&#039; à certains constructeurs. Par exemple, supposons que l&#039;on écrive un programme qui manipule des opérations géométriques dans le plan. On pourra définir le type suivant :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type op =  Symetrie_centrale | Rotation of float | ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Un élément de ce type est soit :&lt;br /&gt;
* une symétrie centrale (pas besoin d&#039;argument),&lt;br /&gt;
* une rotation autour de l&#039;origine, avec un argument de type &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; : l&#039;angle de la rotation. Voici quelques exemples de valeurs de type &amp;quot;&amp;lt;tt&amp;gt;op&amp;lt;/tt&amp;gt;&amp;quot;: &amp;quot;&amp;lt;tt&amp;gt;Symetrie_centrale&amp;lt;/tt&amp;gt;&amp;quot;, &amp;quot;&amp;lt;tt&amp;gt;Rotation (45.0)&amp;lt;/tt&amp;gt;&amp;quot;, &amp;quot;&amp;lt;tt&amp;gt;Rotation (0.0)&amp;lt;/tt&amp;gt;&amp;quot; ou &amp;quot;&amp;lt;tt&amp;gt;Rotation (-360.0)&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Attention :&#039;&#039;&#039; on pourrait penser que &amp;quot;&amp;lt;tt&amp;gt;Rotation&amp;lt;/tt&amp;gt;&amp;quot; est une fonction qui prend un argument. Ça n&#039;est pas le cas. &amp;quot;&amp;lt;tt&amp;gt;Rotation&amp;lt;/tt&amp;gt;&amp;quot; est un &#039;&#039;constructeur&#039;&#039; qui doit nécessairement s&#039;utiliser avec exactement un argument. (Les parenthèses sont facultatives, mais conseillées.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Comme on a le droit d&#039;utiliser n&#039;importe quel type comme argument d&#039;un constructeur, voici ce qu&#039;on pourrait mettre dans le type &amp;quot;&amp;lt;tt&amp;gt;op&amp;lt;/tt&amp;gt;&amp;quot;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type op =  Symetrie_centrale | Rotation of float | Translation of float*float | Homothetie of float&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
De cette manière, on a également les translation selon un vecteur (donné par deux coordonnées flottantes) ou une homothétie de facteur flottant. Voici des nouvelles valeurs dans le type &amp;quot;&amp;lt;tt&amp;gt;op&amp;lt;/tt&amp;gt;&amp;quot; : &amp;quot;&amp;lt;tt&amp;gt;Translation (0.0 , 1.0)&amp;lt;/tt&amp;gt;&amp;quot;, &amp;quot;&amp;lt;tt&amp;gt;Translation (1.3 , 3.5)&amp;lt;/tt&amp;gt;&amp;quot; ou &amp;quot;&amp;lt;tt&amp;gt;Homothetie (2.0)&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les types avec constructeurs sont aussi appelés &#039;&#039;types sommes&#039;&#039;. La raison est que le type des paires (&amp;lt;tt&amp;gt;&#039;&#039;type_1&#039;&#039; * &#039;&#039;type_2&#039;&#039;&amp;lt;/tt&amp;gt;) est appelé &#039;&#039;type produit&#039;&#039; pour une raison évidente : il correspond au produit cartésien. De manière un peu similaire, les type avec constructeurs permettent de faire l&#039;opération &#039;&#039;d&#039;union disjointe&#039;&#039; sur les types. Par exemple, le type &amp;quot;&amp;lt;tt&amp;gt;C1 of &#039;&#039;type_1&#039;&#039; | C2 of &#039;&#039;type_2&#039;&#039;&amp;lt;/tt&amp;gt;&amp;quot; représente exactement la réunion disjointe des types &amp;lt;tt&amp;gt;&#039;&#039;type_1&#039;&#039;&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;&#039;&#039;type_2&#039;&#039;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bien entendu, un constructeur de type somme peut avoir des arguments dont le type est lui même un type somme...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici deux examples de types sommes definis par Caml : le premier est simplement le type &amp;lt;tt&amp;gt;bool&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  type bool = true | false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ce type, comme le type des listes est en fait défini à un niveau plus bas.&lt;br /&gt;
&lt;br /&gt;
Le second type interessant est le type &amp;lt;tt&amp;gt;&#039;a option&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  type &#039;a option = None | Some of &#039;a&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Par exemple, le type &amp;lt;tt&amp;gt;int option&amp;lt;/tt&amp;gt; contient tous les entiers (sous la forme &amp;lt;tt&amp;gt;Some &#039;&#039;n&#039;&#039;&amp;lt;/tt&amp;gt;), mais également une valeur speciale &amp;lt;tt&amp;gt;None&amp;lt;/tt&amp;gt;. On s&#039;en sert en particulier pour modeliser les programmes non totaux. (Ceux qui ne donnent pas toujours une valeurs.) La valeur &amp;lt;tt&amp;gt;None&amp;lt;/tt&amp;gt; joue un peu le role du pointeur &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt; ou de l&#039;entier &amp;lt;tt&amp;gt;-1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Filtrage===&lt;br /&gt;
&lt;br /&gt;
On peut examiner une valeur d&#039;un type somme grâce à l&#039;égalité, mais cela ne permet pas d&#039;accéder aux arguments d&#039;un constructeur :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let weekend (j:jours) = if (j=Samedi) || (j=Dimanche)&lt;br /&gt;
  then true&lt;br /&gt;
  else false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Par exemple, si on veut tester si une opération géométrique (type &amp;lt;tt&amp;gt;op&amp;lt;/tt&amp;gt;) est une rotation, comment faire ?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On utilise le filtrage...&lt;br /&gt;
&lt;br /&gt;
Le filtrage sur un type somme permet de faire comme un &amp;lt;tt&amp;gt;case of&amp;lt;/tt&amp;gt; de Pascal, mais permet en plus de récupérer les valeur des arguments des constructeurs dans des variables.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rotation (o:op) =&lt;br /&gt;
  match o with&lt;br /&gt;
    Symmetrie_centrale -&amp;gt; false&lt;br /&gt;
  | Rotation (a)       -&amp;gt; true&lt;br /&gt;
  | Translation (x,y)  -&amp;gt; false&lt;br /&gt;
  | Homothetie (z)     -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dans le filtrage précèdent, les variables &amp;lt;tt&amp;gt;a&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt; servent à récupérer les valeurs des arguments des constructeurs.&lt;br /&gt;
&lt;br /&gt;
Comme lors du filtrage sur les listes ou les tuples, on peut décider d&#039;ignorer certaines valeurs avec des motifs universels. Voila une seconde version de la fonction précédente :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rotation (o:op) =&lt;br /&gt;
  match o with&lt;br /&gt;
    Rotation (_) -&amp;gt; true&lt;br /&gt;
  | _            -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Types récursifs===&lt;br /&gt;
&lt;br /&gt;
La véritable puissance des types sommes est dans l&#039;utilisation des types sommes récursifs. Nous avons écrit des fonctions récursive, mais il existe également des types récursifs. Par exemple, en Pascal, le type des liste simplement chaînées s&#039;écrit&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
   liste = ^cellule;&lt;br /&gt;
   cellule = record&lt;br /&gt;
               valeur: integer ;&lt;br /&gt;
               suivant: liste;&lt;br /&gt;
             end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
C&#039;est un type récursif : une liste, c&#039;est un pointeur vers une cellule, càd vers un entier et une liste.&lt;br /&gt;
&lt;br /&gt;
En Caml, le type des listes simplement chaînées s&#039;obtient plus simplement avec :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type liste = Cons int*liste&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Autrement dit, une liste est donnée par un entier et une liste.&lt;br /&gt;
&lt;br /&gt;
Comme le pointeur vide n&#039;existe pas en Caml, et que de toute façon, une liste n&#039;est pas vraiment un pointeur, il faut en fait rajouter la possibilité d&#039;avoir la liste vide :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type liste = Vide | Cons int*liste&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; alors que pour définir une fonction récursive, en doit utiliser le mot clé &amp;quot;&amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt;&amp;quot;, pour définir un type, il n&#039;y a pas de mot clé spécial.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finalement, comme les type ont le droit d&#039;avoir des paramètres, on peut donner le type des listes contenant un type arbitraire avec :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type &#039;a liste  =  Vide  |  Cons of &#039;a*&#039;a liste&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Attention :&#039;&#039;&#039;&lt;br /&gt;
# les paramètres d&#039;un types sont précédés d&#039;un guillemet simple,&lt;br /&gt;
# on doit mettre les paramètres avant le nom du type,&lt;br /&gt;
# il ne faut pas oublier de remettre les paramètres lors des appels récursifs au type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La définition du type &amp;lt;tt&amp;gt;liste&amp;lt;/tt&amp;gt; est équivalente à la définition du type &amp;lt;tt&amp;gt;list&amp;lt;/tt&amp;gt; de Caml. Une des différences est que Caml utilise &amp;quot;&amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt;&amp;quot; comme constructeur de liste vide, et &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; plutôt que &amp;quot;&amp;lt;tt&amp;gt;Cons&amp;lt;/tt&amp;gt;&amp;quot;. (Ce ne sont pas des constructeurs valides pour les types définis par l&#039;utilisateur.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut utiliser le filtrage comme pour un type somme non récursif. Voici par exemple la fonction qui convertit une liste à nous en une liste de Caml :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec liste2list : &#039;a liste -&amp;gt; &#039;a list = function &lt;br /&gt;
    Vide -&amp;gt; []&lt;br /&gt;
  | Cons (a,l) -&amp;gt; a::(liste2list l)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
(Remarquez l&#039;utilisation du mot clé &amp;quot;&amp;lt;tt&amp;gt;function&amp;lt;/tt&amp;gt;&amp;quot; à la place de &amp;quot;&amp;lt;tt&amp;gt;fun l -&amp;gt; match l with&amp;lt;/tt&amp;gt;&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
De nombreux types de données sont facilement définissables par un type inductif correspondant. Les seuls types qui posent problème sont les types impératifs (tableaux par exemple) ou les types cycliques (listes doublements chaînées).&lt;br /&gt;
&lt;br /&gt;
Nous verrons plus tard par quoi remplacer ces types, ou comment les utiliser...&lt;br /&gt;
&lt;br /&gt;
==Les structures==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Les exceptions==&lt;br /&gt;
&lt;br /&gt;
==Les librairies==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Les modules==&lt;/div&gt;</summary>
		<author><name>Caroline</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Discussion:INFO421_:_Programmation_fonctionnelle&amp;diff=3687</id>
		<title>Discussion:INFO421 : Programmation fonctionnelle</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Discussion:INFO421_:_Programmation_fonctionnelle&amp;diff=3687"/>
		<updated>2009-01-21T12:42:25Z</updated>

		<summary type="html">&lt;p&gt;Caroline : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Comment commencer une discussion ==&lt;br /&gt;
&lt;br /&gt;
Pour commencer une discussion, il suffit de cliquer sur le &#039;&#039;&#039;&amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;&#039;&#039;&#039; en haut de  la page. Vous pouvez alors rentrer un sujet de discussion et éditer le texte comme pour le wiki.&lt;br /&gt;
&lt;br /&gt;
C&#039;est mieux de signer vos intervention en utilisant l&#039;avant dernier bouton d&#039;édition, ou avec &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
:Pour répondre, il faut « modifier » la section correspondante...&lt;br /&gt;
:Par soucis de visibilité, il est parfois préférable de rajouter une marge à gauche (comme ici). Pour faire ça, il faut commencer votre ligne par un «&amp;lt;tt&amp;gt;:&amp;lt;/tt&amp;gt;». (Ou un «&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;»...)&lt;br /&gt;
&lt;br /&gt;
--[[Utilisateur:Hyvernat|Hyvernat]] 12 janvier 2009 à 13:47 (CET)&lt;br /&gt;
&lt;br /&gt;
== Inscription sur le Wiki ==&lt;br /&gt;
&lt;br /&gt;
Voila, c&#039;est juste pour dire que je me suis inscrit...&lt;br /&gt;
&lt;br /&gt;
--[[Utilisateur:Hyvernat|Hyvernat]] 21 janvier 2009 à 11:01 (CET)&lt;br /&gt;
&lt;br /&gt;
coucou c&#039;est moi&lt;br /&gt;
&lt;br /&gt;
Inscription sur le Wiki&lt;br /&gt;
--[[Utilisateur:LAYER|LAYER]] 21 janvier 2009 à 13:39 (CET)&lt;br /&gt;
&lt;br /&gt;
inscription terminée --[[Utilisateur:Laurent corantin|Laurent corantin]] 21 janvier 2009 à 13:40 (CET)&lt;br /&gt;
&lt;br /&gt;
:: Travail terminé! --[[Utilisateur:Caroline|Caroline]] 21 janvier 2009 à 13:42 (CET)&lt;/div&gt;</summary>
		<author><name>Caroline</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Discussion:INFO421_:_Programmation_fonctionnelle&amp;diff=3686</id>
		<title>Discussion:INFO421 : Programmation fonctionnelle</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Discussion:INFO421_:_Programmation_fonctionnelle&amp;diff=3686"/>
		<updated>2009-01-21T12:41:28Z</updated>

		<summary type="html">&lt;p&gt;Caroline : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Comment commencer une discussion ==&lt;br /&gt;
&lt;br /&gt;
Pour commencer une discussion, il suffit de cliquer sur le &#039;&#039;&#039;&amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;&#039;&#039;&#039; en haut de  la page. Vous pouvez alors rentrer un sujet de discussion et éditer le texte comme pour le wiki.&lt;br /&gt;
&lt;br /&gt;
C&#039;est mieux de signer vos intervention en utilisant l&#039;avant dernier bouton d&#039;édition, ou avec &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
:Pour répondre, il faut « modifier » la section correspondante...&lt;br /&gt;
:Par soucis de visibilité, il est parfois préférable de rajouter une marge à gauche (comme ici). Pour faire ça, il faut commencer votre ligne par un «&amp;lt;tt&amp;gt;:&amp;lt;/tt&amp;gt;». (Ou un «&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;»...)&lt;br /&gt;
&lt;br /&gt;
--[[Utilisateur:Hyvernat|Hyvernat]] 12 janvier 2009 à 13:47 (CET)&lt;br /&gt;
&lt;br /&gt;
== Inscription sur le Wiki ==&lt;br /&gt;
&lt;br /&gt;
Voila, c&#039;est juste pour dire que je me suis inscrit...&lt;br /&gt;
&lt;br /&gt;
--[[Utilisateur:Hyvernat|Hyvernat]] 21 janvier 2009 à 11:01 (CET)&lt;br /&gt;
&lt;br /&gt;
coucou c&#039;est moi&lt;br /&gt;
&lt;br /&gt;
Inscription sur le Wiki&lt;br /&gt;
--[[Utilisateur:LAYER|LAYER]] 21 janvier 2009 à 13:39 (CET)&lt;br /&gt;
&lt;br /&gt;
inscription terminée --[[Utilisateur:Laurent corantin|Laurent corantin]] 21 janvier 2009 à 13:40 (CET)&lt;br /&gt;
&lt;br /&gt;
:: Travail terminé! --&lt;/div&gt;</summary>
		<author><name>Caroline</name></author>
	</entry>
</feed>