<?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=Lachand</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=Lachand"/>
	<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php/Sp%C3%A9cial:Contributions/Lachand"/>
	<updated>2026-05-21T05:28:16Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.39.4</generator>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Discussion_utilisateur:Hyvernat&amp;diff=5932</id>
		<title>Discussion utilisateur:Hyvernat</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Discussion_utilisateur:Hyvernat&amp;diff=5932"/>
		<updated>2013-02-12T19:08:04Z</updated>

		<summary type="html">&lt;p&gt;Lachand : Page blanchie&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Lachand</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Discussion_utilisateur:Hyvernat&amp;diff=5931</id>
		<title>Discussion utilisateur:Hyvernat</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Discussion_utilisateur:Hyvernat&amp;diff=5931"/>
		<updated>2013-02-12T19:07:10Z</updated>

		<summary type="html">&lt;p&gt;Lachand : Page créée avec « Bonjour, le lien que vous avez mis au début du cours d&amp;#039;info 421 http://meta.wikimedia.org/wiki/Aide:Contenu est mort »&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bonjour, le lien que vous avez mis au début du cours d&#039;info 421 http://meta.wikimedia.org/wiki/Aide:Contenu est mort&lt;/div&gt;</summary>
		<author><name>Lachand</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO421_:_Programmation_fonctionnelle&amp;diff=5930</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=5930"/>
		<updated>2013-02-12T18:58:19Z</updated>

		<summary type="html">&lt;p&gt;Lachand : /* Les types algébriques */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-421 : 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;
== Détails techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Compléments de cours, TD et TP ===&lt;br /&gt;
&lt;br /&gt;
==== Installer 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;
* Sous MacOS : il semblerait qu&#039;il y ait des paquets MacPorts pour &amp;lt;tt&amp;gt;ocaml&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;emacs&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;tuareg-mode.el&amp;lt;/tt&amp;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;
Pour les exemples simples, vous pouvez aussi utiliser [http://try.ocamlpro.com/ OCaml en ligne]&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;
* 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;
* Le livre de Jason Hickey [http://files.metaprl.org/doc/ocaml-book.pdf Introduction to Objective Caml] (en anglais).&lt;br /&gt;
&lt;br /&gt;
==== Cours ====&lt;br /&gt;
&lt;br /&gt;
==== TD et TP ====&lt;br /&gt;
&lt;br /&gt;
* [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/1213/info421/td1.pdf TD1 : premières expressions en Caml (pdf)]&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;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Attention :&#039;&#039; il ne s&#039;agit pas d&#039;un cours de programmation fonctionelle&lt;br /&gt;
	&amp;lt;/blockquote&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;
=== 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;
* année &#039;80 : Caml (1987), puis CamlLight(1990), puis OCaml(1996), développé&lt;br /&gt;
à l&#039;INRIA. (Dernière version en octobre 2012.)&lt;br /&gt;
* années &#039;90 : Python (version 1.0 en 1994).&lt;br /&gt;
* années &#039;90 : PHP (version 1.0 en 1995).&lt;br /&gt;
* années &#039;90 : Java (version 1.0 en 1996).&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;
&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;&#039;impératifs&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un des slogans de la programmation fonctionnelle en général est&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;&amp;lt;u&amp;gt;Les fonctions sont des valeurs comme les autres&amp;lt;/u&amp;gt;&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
et c&#039;est de là que vient la terminologie... En particulier, il n&#039;y a pas de différence entre les &#039;&#039;instructions&#039;&#039; (qui ont un effet) et les &#039;&#039;expressions&#039;&#039; (qui ont une valeur). Par exemple, en Python,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
x = x+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ou&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if delta &amp;lt; 0:&lt;br /&gt;
    print(&amp;quot;Il n&#039;y a pas de solution&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sont des &#039;&#039;instructions&#039;&#039; : on ne peut pas les mettre dans une variable.&lt;br /&gt;
&lt;br /&gt;
Comme nous le verront, cela a des 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), statiquement typé (nous verrons ce que cela veut dire) qui supporte plusieurs styles de programmation :&lt;br /&gt;
&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 principalement le style fonctionnel, et un peu le style impératif en fin de semestre.&lt;br /&gt;
&lt;br /&gt;
Voici quelques aspects importants du langages que nous essayeront d&#039;aborder pendant le cours :&lt;br /&gt;
&lt;br /&gt;
* fonctions comme valeurs,&lt;br /&gt;
* types de données &#039;&#039;algébriques&#039;&#039;&lt;br /&gt;
* polymorphisme,&lt;br /&gt;
* système d&#039;exceptions,&lt;br /&gt;
* support pour des références et des données mutables (programmation « impure »),&lt;br /&gt;
* système de modules et de foncteurs,&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;récursivité&#039;&#039; sera fondamentale pendant toute la durée du cours...&lt;br /&gt;
&lt;br /&gt;
Un aspect intéressant du langage est que c&#039;est :&lt;br /&gt;
&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;
=== Autres langages fonctionnels ===&lt;br /&gt;
&lt;br /&gt;
Il existe de nombreux autres langages fonctionnels. Par exemple :&lt;br /&gt;
&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;
** Common LISP : [http://en.wikipedia.org/wiki/Common_LISP Wikipedia],&lt;br /&gt;
** Scheme : [http://en.wikipedia.org/wiki/Scheme_%28programming_language%29 Wikipedia].&lt;br /&gt;
* Haskell : [http://en.wikipedia.org/wiki/Haskell_%28programming_language%29 Wikipedia] (inspiré en grande partie de [http://en.wikipedia.org/wiki/Miranda_%28programming_language%29 Miranda]).&lt;br /&gt;
&lt;br /&gt;
Plusieurs langages impératifs intègrent maintenant des aspects propres des langages fonctionnels : Python, Scala, ...&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;
&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;
* analyse de programmes critiques : [http://www.astree.ens.fr/ Astrée],&lt;br /&gt;
* informatique financiere : [http://www.janestreet.com Janestreet Capital] et [http://www.lexifi.com Lexifi].&lt;br /&gt;
&lt;br /&gt;
La viabilité du paradigme fonctionnel se retrouve également dans le langage Erlang ([http://fr.wikipedia.org/wiki/Erlang_%28langage%29 Wikipedia]), un langage fonctionnel développé par Ericsson pour la programmation concurrente de systèmes temps réels.&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, les types algébriques 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;
# 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;
Un des slogans de la programmation fonctionnelle est &#039;&#039;tout est une valeur, ou plus précisément,&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Toute expression &amp;lt;u&amp;gt;a&amp;lt;/u&amp;gt; une valeur.&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette idée n&#039;est pas présente en Python 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: a=12 else: a=13&amp;lt;/tt&amp;gt;&amp;quot; par exemple). En Python, les instructions sont en général séparées par des retours à la ligne 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;
&lt;br /&gt;
* les fonctions du langage (addition, multiplication, opérateurs logiques),&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;
* les relations mathématiques (égalité, plus grand), ... qui sont juste des fonctions renvoyant des booléens,&lt;br /&gt;
* les constantes du langage,&lt;br /&gt;
* les variables de l&#039;environnement,&lt;br /&gt;
* &#039;&#039;les valeurs (en particulier les fonctions) définies par le programmeur&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Bien entendu, comme Caml est typé, il faut respecter 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;
&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;) et les opérations &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt; (et) et &amp;lt;tt&amp;gt;||&amp;lt;/tt&amp;gt; (ou).&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&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;&amp;lt;/math&amp;gt; et &amp;lt;math&amp;gt;2&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;-1&amp;lt;/math&amp;gt;. (Les entiers Caml sont stockés sur 31 bits...) Les opérations associés sont &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; (pour la division entière) et &amp;lt;tt&amp;gt;mod&amp;lt;/tt&amp;gt; (pour le modulo).&lt;br /&gt;
* Les flottants : type &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; pour les réels en virgule flottante. Les opérations usuelles sont &amp;lt;tt&amp;gt;+.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*.&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;/.&amp;lt;/tt&amp;gt;.&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;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* exemples ... *)&lt;br /&gt;
&amp;lt;/source&amp;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écessaire. 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;
=== définitions et 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;, ...&lt;br /&gt;
&lt;br /&gt;
Certaines des variables de l&#039;environnement correspondent à des paramètres de fonction en cours de définition. Ces variables n&#039;ont pas de valeur, mais seulement un type.&lt;br /&gt;
&lt;br /&gt;
==== Environnement ====&lt;br /&gt;
&lt;br /&gt;
* Liste de paires &amp;lt;tt&amp;gt;nom&amp;lt;/tt&amp;gt; / &amp;lt;tt&amp;gt;valeur&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* une nouvelle definition remplace la précédente mais ne l&#039;efface pas, (on ne met pas une valeur à jours)&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;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;let nom = expr&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 nom1 = expr1 and nom2 = expr2&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 nom1 = expr1 and nom2 = expr2&amp;lt;/tt&amp;gt; permet de rajouter des définitions mutuellement récursives.&lt;br /&gt;
&lt;br /&gt;
On peut toujours 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;
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;
&lt;br /&gt;
* : float = 3.1415&lt;br /&gt;
&amp;lt;/source&amp;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 nom = expr1 in expr2&amp;lt;/tt&amp;gt;. Ceci ajoute la définition &amp;lt;tt&amp;gt;nom = expr1&amp;lt;/tt&amp;gt; dans l&#039;environnement, mais seulement pour l&#039;évaluation de l&#039;expression &amp;lt;tt&amp;gt;expr2&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;
&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 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 dont 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;interprète Caml :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # String.length ;;&lt;br /&gt;
&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 fonction est définie comme une variable avec un &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt; et en utilisant le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f = fun n -&amp;gt; n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine = fun n -&amp;gt; int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Une fonction avec plusieurs argument est définie de la même manière avec&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let moyenne3 = fun x y z -&amp;gt; (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le type d&#039;une fonction à plusieurs argument est noté en mettant plusieurs types à gauche de la flèche &amp;lt;tt&amp;gt;-&amp;gt;&amp;lt;/tt&amp;gt;, comme ci dessus : &amp;lt;tt&amp;gt;type_arg1 -&amp;gt; type_arg2 -&amp;gt; type_arg3 -&amp;gt; type_resultat&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarques :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* notez l&#039;absence de mot clé &amp;lt;tt&amp;gt;return&amp;lt;/tt&amp;gt; et l&#039;absence de virgules pour séparer les différents arguments !&lt;br /&gt;
* Le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; permet de définir des fonctions sans leur donner de nom, ce qui n&#039;est pas possible dans les langages comme C ou Java...&lt;br /&gt;
&lt;br /&gt;
On peut également utiliser un raccourci pour définir une fonction sans utiliser le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; : il suffit de mettre les arguments de la fonction avant le signe égal :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f n = n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine n = int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let moyenne3 x y z = (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour appliquer une fonction à des arguments, on écrit simplement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Il n&#039;y a ni parenthèse, ni virgule. Les parenthèses peuvent cependant être nécessaires pour différencier&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 (-0.333 *. 6.)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
et&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(moyenne3 13.5 17.0 -0.333) *. 6.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ou pour que Caml lise correctement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 (17.0 -. 12.0) -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Fonctions récursives ====&lt;br /&gt;
&lt;br /&gt;
Si on essaie de définir une fonction récursivement :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let f n = if (n&amp;lt;1) then 0 else n + f (n-1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Caml répond&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
Error: Unbound value f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
car &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; n&#039;est pas présente dans l&#039;environnement.&lt;br /&gt;
&lt;br /&gt;
Pour rajouter &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; comme variable active (sans valeur) et pouvoir faire une définition récursive, il faut utiliser le mot clé &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let rec f n = if (n&amp;lt;1) then 0 else n + f (n-1);;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les définitions locales peuvent elles aussi être récursives (&amp;lt;tt&amp;gt;let rec ... in ...&amp;lt;/tt&amp;gt;) ou 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;
==== fonctions d&#039;ordre supérieur ====&lt;br /&gt;
&lt;br /&gt;
TODO&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;
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;
Contrairement au cas des tuples, 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; 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;
On peut ajouter un élement devant une liste avec l&#039;opérateur &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; et 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;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# 5::[1;2;3;4] ;;&lt;br /&gt;
- : int list = [5; 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; ne dépend pas de la taille des listes mises en jeux. Par contre, la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot; dépend proportionnellement de la taille de son premier argument. Il faut donc toujour privilégier &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; par rapport à &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot;. En particulier, il est en général mauvais de rajouter des élément en fin de liste en utilisant &amp;quot;&amp;lt;tt&amp;gt;l @ [e]&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Filtrage, première partie : tuples et listes ===&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;filtrage&#039;&#039;, aussi appelé &amp;quot;pattern-matching&amp;quot; est un outils clé pour la programmation en Caml. L&#039;idée est de décomposer une valeur en &amp;quot;sous-valeurs&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les tuples ====&lt;br /&gt;
&lt;br /&gt;
Comme une paire est de la forme &amp;lt;tt&amp;gt;(x,y)&amp;lt;/tt&amp;gt;, on peut décomposer une valeur de type &amp;lt;tt&amp;gt;a*b&amp;lt;/tt&amp;gt; en deux sous valeurs. Voici un exemple de syntaxe : le code de la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt; :&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;
&lt;br /&gt;
Pour évaluer &amp;quot;&amp;lt;tt&amp;gt;premier e&amp;lt;/tt&amp;gt;&amp;quot;, Caml regarde le premier argument &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; et essaie de faire coïncider &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 maintenant récupérer la deuxième composante d&#039;un triplet de la manière suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let second3 t = match t with&lt;br /&gt;
    (_, y, _) -&amp;gt; y&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Notez l&#039;utilisation de &amp;quot;&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;&amp;quot; pour donner la position d&#039;une sous-valeur qui ne sert à rien.&lt;br /&gt;
&lt;br /&gt;
Toutes les variables présentes dans le &#039;&#039;motif&#039;&#039; (la partie à gauche de la flèche) se retrouvent dans l&#039;environnement avec pour valeur, la sous-valeur appropriée. &amp;lt;u&amp;gt;Attention,&amp;lt;/u&amp;gt; ces variables ne se retrouvent dans l&#039;environnement que dans la partie droite de la flèche.&lt;br /&gt;
Ces variables remplacent (temporairement) les variables de même nom qui pouvaient se trouver dans l&#039;environnement. Par exemple, la fonction :&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;
est exactement la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les listes ====&lt;br /&gt;
&lt;br /&gt;
On peut décomposer une liste en deux sous-valeurs :&lt;br /&gt;
&lt;br /&gt;
* le premier élément de la liste,&lt;br /&gt;
* la suite de la liste.&lt;br /&gt;
&lt;br /&gt;
Autrement dit, si la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; n&#039;est pas vide, on peut la décomposer en &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt;. Comme il est possible que la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; soit vide, il y a en fait deux manière de décomposer &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (sans aucune sous-valeur),&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt; (avec deux sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
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;
Les différents cas sont séparés par le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
On peut également décomposer une liste en 3 sous-valeurs : le premier élément, le second élément et la suite de la liste. Dans ce cas, il a trois cas pour une liste arbitraire :&lt;br /&gt;
&lt;br /&gt;
* elle est vide &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (aucune sous-valeur),&lt;br /&gt;
* elle ne contient qu&#039;une seul élément &amp;lt;tt&amp;gt;[e]&amp;lt;/tt&amp;gt; (une sous-valeur),&lt;br /&gt;
* elle contient un premier élément, un deuxième élément, et une suite &amp;lt;tt&amp;gt;a::b::q&amp;lt;/tt&amp;gt; (trois sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
On peut par exemple écrire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus l = match l with&lt;br /&gt;
    [] -&amp;gt; false&lt;br /&gt;
  | [a] -&amp;gt; false&lt;br /&gt;
  | a::b::q -&amp;gt; true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme on peut toujours décomposer une valeur en une sous-valeur (la valeur elle même), on peut toujours avoir un motif de la forme &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;. Toutes les valeurs pourront être décomposées de cette manière, et il faut donc que ce motif soit le dernier. (Sinon, les motifs suivants ne servent à rien...) On parle de motif &#039;&#039;universel&#039;&#039;. (On peut utiliser &amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt; comme motif universel.) Par exemple, on peut réecrire l&#039;exemple précédent :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus&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;
==== Compléments ====&lt;br /&gt;
&lt;br /&gt;
# On peut ajouter des constantes dans les motifs. Le motif ne sera utilisé que lorsque la sous-valeur correspondantes a la valeurs correspondante. Par exemple, si on modélise les entiers de Gauss (« entiers complexes ») par des paires d&#039;entiers, on peut définir :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let imaginaire_pur c = match c with&lt;br /&gt;
    (0,0) -&amp;gt; false&lt;br /&gt;
  | (0,_) -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# On peut grouper des motifs différents pour faire la même chose. Il faut que les variables qui apparaissent dans les motifs soient les mêmes, et qu&#039;elles aient le même type :&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 | 2::_::_::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;
# on peut « garder » les motifs&amp;quot; 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;
&amp;lt;u&amp;gt;Attention&amp;lt;/u&amp;gt; dans le cas où vous utilisez &amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt; : il est conseillé de terminer votre filtrage avec un motif universel pour être sûr que vous n&#039;avez pas oublié de cas.&lt;br /&gt;
# 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;
&lt;br /&gt;
=== Transparence référentielle ===&lt;br /&gt;
&lt;br /&gt;
=== Les types algébriques ===&lt;br /&gt;
&lt;br /&gt;
On peut défnir un synonyme de type avec le mot clef &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
Exemple : &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type point = float*float&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Types énumérés ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On donne tous les éléments du type&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type jours = Lundi | Mardi | Mercredi | ...&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Type avec 7 éléments. Les éléments commencent forcément par une majuscule.&lt;br /&gt;
&lt;br /&gt;
On peut comparer des éléments avec &amp;quot;=&amp;quot;, &amp;quot;&amp;lt;&amp;quot; et &amp;quot;&amp;gt;&amp;quot; (&amp;lt; et &amp;gt; sont à éviter, il vaut mieux&lt;br /&gt;
écrire une fonction pour comparer) On peut aussi faire du filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let week_end j = match j with&lt;br /&gt;
Samedi -&amp;gt; true&lt;br /&gt;
   | Dimanche -&amp;gt; true&lt;br /&gt;
   | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Construction de types paramètres ====&lt;br /&gt;
 &lt;br /&gt;
Exemple : type des transformations de l&#039;espace avec :&lt;br /&gt;
- Translation&lt;br /&gt;
- Rotation&lt;br /&gt;
- Symetrie&lt;br /&gt;
On aura alors des constructeurs avec des paramètres :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type transformation =&lt;br /&gt;
Rotation of int*point&lt;br /&gt;
| Translation of point&lt;br /&gt;
| SymCentrale of point&lt;br /&gt;
| Homothetie of float*point&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On n&#039;a pas donné explicitement tous les éléments, mais on les a donné implicitement.&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rien = Translation (0.0,0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Autre exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let fait quelquechose t=&lt;br /&gt;
match t with&lt;br /&gt;
Rotation(a, (x, y)− &amp;gt; a mod360! = 0&lt;br /&gt;
|T ranslation(x, y)− &amp;gt; x! = 0.0 &amp;amp;&amp;amp; y! = 0.0&lt;br /&gt;
|SymCentrale(x, y)− &amp;gt; true&lt;br /&gt;
|Homotetie(x, (−, −))− &amp;gt; r! = 1, 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Les types récursifs ====&lt;br /&gt;
&lt;br /&gt;
En Caml&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type node = Node of int*node&lt;br /&gt;
| Vide&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
exemple d&#039;éléments de &amp;quot;node&amp;quot; :&lt;br /&gt;
- Vide&lt;br /&gt;
- Node(0,Vide)&lt;br /&gt;
- Node(1,Node(2,Node(3, Vide)))&lt;br /&gt;
&lt;br /&gt;
Le type &amp;quot;node&amp;quot; est un type récursif. Comme les fonctions récursivent doivent avoir des cas&lt;br /&gt;
de base, les types récursifs doivent avoir des constructeurs &amp;quot;de base&amp;quot; (non récursifs). On peut&lt;br /&gt;
comparer des éléments avec &amp;quot;=&amp;quot;. On peut aussi utiliser le filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
Vide -&amp;gt; 0&lt;br /&gt;
|Node(_,l)-&amp;gt;1+taille l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction taille sur les listes Caml suit le même schéma avec les abréviations Caml.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
| a ::l-&amp;gt;1+taille&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ceci explique la différence entre :: (constructeur) et @ (fonction récursive)&lt;br /&gt;
&lt;br /&gt;
Exemple de type récursif, les arbres binaires :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type bin = Vide | Noeud of int*bin*bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
arbre naire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type arbre n_aire = &lt;br /&gt;
Vide|Node of int ∗ (arbre_naire list)(bancal)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Les structures ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== La récursivité terminale ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les exceptions ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Aspects impératifs dans Caml ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les modules ==&lt;/div&gt;</summary>
		<author><name>Lachand</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO421_:_Programmation_fonctionnelle&amp;diff=5929</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=5929"/>
		<updated>2013-02-12T18:39:30Z</updated>

		<summary type="html">&lt;p&gt;Lachand : /* Les types algébriques */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-421 : 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;
== Détails techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Compléments de cours, TD et TP ===&lt;br /&gt;
&lt;br /&gt;
==== Installer 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;
* Sous MacOS : il semblerait qu&#039;il y ait des paquets MacPorts pour &amp;lt;tt&amp;gt;ocaml&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;emacs&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;tuareg-mode.el&amp;lt;/tt&amp;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;
Pour les exemples simples, vous pouvez aussi utiliser [http://try.ocamlpro.com/ OCaml en ligne]&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;
* 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;
* Le livre de Jason Hickey [http://files.metaprl.org/doc/ocaml-book.pdf Introduction to Objective Caml] (en anglais).&lt;br /&gt;
&lt;br /&gt;
==== Cours ====&lt;br /&gt;
&lt;br /&gt;
==== TD et TP ====&lt;br /&gt;
&lt;br /&gt;
* [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/1213/info421/td1.pdf TD1 : premières expressions en Caml (pdf)]&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;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Attention :&#039;&#039; il ne s&#039;agit pas d&#039;un cours de programmation fonctionelle&lt;br /&gt;
	&amp;lt;/blockquote&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;
=== 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;
* année &#039;80 : Caml (1987), puis CamlLight(1990), puis OCaml(1996), développé&lt;br /&gt;
à l&#039;INRIA. (Dernière version en octobre 2012.)&lt;br /&gt;
* années &#039;90 : Python (version 1.0 en 1994).&lt;br /&gt;
* années &#039;90 : PHP (version 1.0 en 1995).&lt;br /&gt;
* années &#039;90 : Java (version 1.0 en 1996).&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;
&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;&#039;impératifs&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un des slogans de la programmation fonctionnelle en général est&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;&amp;lt;u&amp;gt;Les fonctions sont des valeurs comme les autres&amp;lt;/u&amp;gt;&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
et c&#039;est de là que vient la terminologie... En particulier, il n&#039;y a pas de différence entre les &#039;&#039;instructions&#039;&#039; (qui ont un effet) et les &#039;&#039;expressions&#039;&#039; (qui ont une valeur). Par exemple, en Python,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
x = x+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ou&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if delta &amp;lt; 0:&lt;br /&gt;
    print(&amp;quot;Il n&#039;y a pas de solution&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sont des &#039;&#039;instructions&#039;&#039; : on ne peut pas les mettre dans une variable.&lt;br /&gt;
&lt;br /&gt;
Comme nous le verront, cela a des 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), statiquement typé (nous verrons ce que cela veut dire) qui supporte plusieurs styles de programmation :&lt;br /&gt;
&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 principalement le style fonctionnel, et un peu le style impératif en fin de semestre.&lt;br /&gt;
&lt;br /&gt;
Voici quelques aspects importants du langages que nous essayeront d&#039;aborder pendant le cours :&lt;br /&gt;
&lt;br /&gt;
* fonctions comme valeurs,&lt;br /&gt;
* types de données &#039;&#039;algébriques&#039;&#039;&lt;br /&gt;
* polymorphisme,&lt;br /&gt;
* système d&#039;exceptions,&lt;br /&gt;
* support pour des références et des données mutables (programmation « impure »),&lt;br /&gt;
* système de modules et de foncteurs,&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;récursivité&#039;&#039; sera fondamentale pendant toute la durée du cours...&lt;br /&gt;
&lt;br /&gt;
Un aspect intéressant du langage est que c&#039;est :&lt;br /&gt;
&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;
=== Autres langages fonctionnels ===&lt;br /&gt;
&lt;br /&gt;
Il existe de nombreux autres langages fonctionnels. Par exemple :&lt;br /&gt;
&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;
** Common LISP : [http://en.wikipedia.org/wiki/Common_LISP Wikipedia],&lt;br /&gt;
** Scheme : [http://en.wikipedia.org/wiki/Scheme_%28programming_language%29 Wikipedia].&lt;br /&gt;
* Haskell : [http://en.wikipedia.org/wiki/Haskell_%28programming_language%29 Wikipedia] (inspiré en grande partie de [http://en.wikipedia.org/wiki/Miranda_%28programming_language%29 Miranda]).&lt;br /&gt;
&lt;br /&gt;
Plusieurs langages impératifs intègrent maintenant des aspects propres des langages fonctionnels : Python, Scala, ...&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;
&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;
* analyse de programmes critiques : [http://www.astree.ens.fr/ Astrée],&lt;br /&gt;
* informatique financiere : [http://www.janestreet.com Janestreet Capital] et [http://www.lexifi.com Lexifi].&lt;br /&gt;
&lt;br /&gt;
La viabilité du paradigme fonctionnel se retrouve également dans le langage Erlang ([http://fr.wikipedia.org/wiki/Erlang_%28langage%29 Wikipedia]), un langage fonctionnel développé par Ericsson pour la programmation concurrente de systèmes temps réels.&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, les types algébriques 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;
# 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;
Un des slogans de la programmation fonctionnelle est &#039;&#039;tout est une valeur, ou plus précisément,&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Toute expression &amp;lt;u&amp;gt;a&amp;lt;/u&amp;gt; une valeur.&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette idée n&#039;est pas présente en Python 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: a=12 else: a=13&amp;lt;/tt&amp;gt;&amp;quot; par exemple). En Python, les instructions sont en général séparées par des retours à la ligne 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;
&lt;br /&gt;
* les fonctions du langage (addition, multiplication, opérateurs logiques),&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;
* les relations mathématiques (égalité, plus grand), ... qui sont juste des fonctions renvoyant des booléens,&lt;br /&gt;
* les constantes du langage,&lt;br /&gt;
* les variables de l&#039;environnement,&lt;br /&gt;
* &#039;&#039;les valeurs (en particulier les fonctions) définies par le programmeur&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Bien entendu, comme Caml est typé, il faut respecter 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;
&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;) et les opérations &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt; (et) et &amp;lt;tt&amp;gt;||&amp;lt;/tt&amp;gt; (ou).&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&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;&amp;lt;/math&amp;gt; et &amp;lt;math&amp;gt;2&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;-1&amp;lt;/math&amp;gt;. (Les entiers Caml sont stockés sur 31 bits...) Les opérations associés sont &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; (pour la division entière) et &amp;lt;tt&amp;gt;mod&amp;lt;/tt&amp;gt; (pour le modulo).&lt;br /&gt;
* Les flottants : type &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; pour les réels en virgule flottante. Les opérations usuelles sont &amp;lt;tt&amp;gt;+.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*.&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;/.&amp;lt;/tt&amp;gt;.&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;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* exemples ... *)&lt;br /&gt;
&amp;lt;/source&amp;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écessaire. 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;
=== définitions et 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;, ...&lt;br /&gt;
&lt;br /&gt;
Certaines des variables de l&#039;environnement correspondent à des paramètres de fonction en cours de définition. Ces variables n&#039;ont pas de valeur, mais seulement un type.&lt;br /&gt;
&lt;br /&gt;
==== Environnement ====&lt;br /&gt;
&lt;br /&gt;
* Liste de paires &amp;lt;tt&amp;gt;nom&amp;lt;/tt&amp;gt; / &amp;lt;tt&amp;gt;valeur&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* une nouvelle definition remplace la précédente mais ne l&#039;efface pas, (on ne met pas une valeur à jours)&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;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;let nom = expr&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 nom1 = expr1 and nom2 = expr2&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 nom1 = expr1 and nom2 = expr2&amp;lt;/tt&amp;gt; permet de rajouter des définitions mutuellement récursives.&lt;br /&gt;
&lt;br /&gt;
On peut toujours 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;
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;
&lt;br /&gt;
* : float = 3.1415&lt;br /&gt;
&amp;lt;/source&amp;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 nom = expr1 in expr2&amp;lt;/tt&amp;gt;. Ceci ajoute la définition &amp;lt;tt&amp;gt;nom = expr1&amp;lt;/tt&amp;gt; dans l&#039;environnement, mais seulement pour l&#039;évaluation de l&#039;expression &amp;lt;tt&amp;gt;expr2&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;
&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 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 dont 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;interprète Caml :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # String.length ;;&lt;br /&gt;
&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 fonction est définie comme une variable avec un &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt; et en utilisant le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f = fun n -&amp;gt; n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine = fun n -&amp;gt; int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Une fonction avec plusieurs argument est définie de la même manière avec&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let moyenne3 = fun x y z -&amp;gt; (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le type d&#039;une fonction à plusieurs argument est noté en mettant plusieurs types à gauche de la flèche &amp;lt;tt&amp;gt;-&amp;gt;&amp;lt;/tt&amp;gt;, comme ci dessus : &amp;lt;tt&amp;gt;type_arg1 -&amp;gt; type_arg2 -&amp;gt; type_arg3 -&amp;gt; type_resultat&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarques :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* notez l&#039;absence de mot clé &amp;lt;tt&amp;gt;return&amp;lt;/tt&amp;gt; et l&#039;absence de virgules pour séparer les différents arguments !&lt;br /&gt;
* Le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; permet de définir des fonctions sans leur donner de nom, ce qui n&#039;est pas possible dans les langages comme C ou Java...&lt;br /&gt;
&lt;br /&gt;
On peut également utiliser un raccourci pour définir une fonction sans utiliser le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; : il suffit de mettre les arguments de la fonction avant le signe égal :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f n = n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine n = int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let moyenne3 x y z = (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour appliquer une fonction à des arguments, on écrit simplement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Il n&#039;y a ni parenthèse, ni virgule. Les parenthèses peuvent cependant être nécessaires pour différencier&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 (-0.333 *. 6.)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
et&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(moyenne3 13.5 17.0 -0.333) *. 6.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ou pour que Caml lise correctement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 (17.0 -. 12.0) -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Fonctions récursives ====&lt;br /&gt;
&lt;br /&gt;
Si on essaie de définir une fonction récursivement :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let f n = if (n&amp;lt;1) then 0 else n + f (n-1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Caml répond&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
Error: Unbound value f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
car &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; n&#039;est pas présente dans l&#039;environnement.&lt;br /&gt;
&lt;br /&gt;
Pour rajouter &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; comme variable active (sans valeur) et pouvoir faire une définition récursive, il faut utiliser le mot clé &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let rec f n = if (n&amp;lt;1) then 0 else n + f (n-1);;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les définitions locales peuvent elles aussi être récursives (&amp;lt;tt&amp;gt;let rec ... in ...&amp;lt;/tt&amp;gt;) ou 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;
==== fonctions d&#039;ordre supérieur ====&lt;br /&gt;
&lt;br /&gt;
TODO&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;
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;
Contrairement au cas des tuples, 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; 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;
On peut ajouter un élement devant une liste avec l&#039;opérateur &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; et 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;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# 5::[1;2;3;4] ;;&lt;br /&gt;
- : int list = [5; 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; ne dépend pas de la taille des listes mises en jeux. Par contre, la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot; dépend proportionnellement de la taille de son premier argument. Il faut donc toujour privilégier &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; par rapport à &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot;. En particulier, il est en général mauvais de rajouter des élément en fin de liste en utilisant &amp;quot;&amp;lt;tt&amp;gt;l @ [e]&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Filtrage, première partie : tuples et listes ===&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;filtrage&#039;&#039;, aussi appelé &amp;quot;pattern-matching&amp;quot; est un outils clé pour la programmation en Caml. L&#039;idée est de décomposer une valeur en &amp;quot;sous-valeurs&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les tuples ====&lt;br /&gt;
&lt;br /&gt;
Comme une paire est de la forme &amp;lt;tt&amp;gt;(x,y)&amp;lt;/tt&amp;gt;, on peut décomposer une valeur de type &amp;lt;tt&amp;gt;a*b&amp;lt;/tt&amp;gt; en deux sous valeurs. Voici un exemple de syntaxe : le code de la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt; :&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;
&lt;br /&gt;
Pour évaluer &amp;quot;&amp;lt;tt&amp;gt;premier e&amp;lt;/tt&amp;gt;&amp;quot;, Caml regarde le premier argument &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; et essaie de faire coïncider &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 maintenant récupérer la deuxième composante d&#039;un triplet de la manière suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let second3 t = match t with&lt;br /&gt;
    (_, y, _) -&amp;gt; y&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Notez l&#039;utilisation de &amp;quot;&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;&amp;quot; pour donner la position d&#039;une sous-valeur qui ne sert à rien.&lt;br /&gt;
&lt;br /&gt;
Toutes les variables présentes dans le &#039;&#039;motif&#039;&#039; (la partie à gauche de la flèche) se retrouvent dans l&#039;environnement avec pour valeur, la sous-valeur appropriée. &amp;lt;u&amp;gt;Attention,&amp;lt;/u&amp;gt; ces variables ne se retrouvent dans l&#039;environnement que dans la partie droite de la flèche.&lt;br /&gt;
Ces variables remplacent (temporairement) les variables de même nom qui pouvaient se trouver dans l&#039;environnement. Par exemple, la fonction :&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;
est exactement la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les listes ====&lt;br /&gt;
&lt;br /&gt;
On peut décomposer une liste en deux sous-valeurs :&lt;br /&gt;
&lt;br /&gt;
* le premier élément de la liste,&lt;br /&gt;
* la suite de la liste.&lt;br /&gt;
&lt;br /&gt;
Autrement dit, si la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; n&#039;est pas vide, on peut la décomposer en &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt;. Comme il est possible que la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; soit vide, il y a en fait deux manière de décomposer &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (sans aucune sous-valeur),&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt; (avec deux sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
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;
Les différents cas sont séparés par le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
On peut également décomposer une liste en 3 sous-valeurs : le premier élément, le second élément et la suite de la liste. Dans ce cas, il a trois cas pour une liste arbitraire :&lt;br /&gt;
&lt;br /&gt;
* elle est vide &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (aucune sous-valeur),&lt;br /&gt;
* elle ne contient qu&#039;une seul élément &amp;lt;tt&amp;gt;[e]&amp;lt;/tt&amp;gt; (une sous-valeur),&lt;br /&gt;
* elle contient un premier élément, un deuxième élément, et une suite &amp;lt;tt&amp;gt;a::b::q&amp;lt;/tt&amp;gt; (trois sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
On peut par exemple écrire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus l = match l with&lt;br /&gt;
    [] -&amp;gt; false&lt;br /&gt;
  | [a] -&amp;gt; false&lt;br /&gt;
  | a::b::q -&amp;gt; true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme on peut toujours décomposer une valeur en une sous-valeur (la valeur elle même), on peut toujours avoir un motif de la forme &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;. Toutes les valeurs pourront être décomposées de cette manière, et il faut donc que ce motif soit le dernier. (Sinon, les motifs suivants ne servent à rien...) On parle de motif &#039;&#039;universel&#039;&#039;. (On peut utiliser &amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt; comme motif universel.) Par exemple, on peut réecrire l&#039;exemple précédent :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus&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;
==== Compléments ====&lt;br /&gt;
&lt;br /&gt;
# On peut ajouter des constantes dans les motifs. Le motif ne sera utilisé que lorsque la sous-valeur correspondantes a la valeurs correspondante. Par exemple, si on modélise les entiers de Gauss (« entiers complexes ») par des paires d&#039;entiers, on peut définir :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let imaginaire_pur c = match c with&lt;br /&gt;
    (0,0) -&amp;gt; false&lt;br /&gt;
  | (0,_) -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# On peut grouper des motifs différents pour faire la même chose. Il faut que les variables qui apparaissent dans les motifs soient les mêmes, et qu&#039;elles aient le même type :&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 | 2::_::_::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;
# on peut « garder » les motifs&amp;quot; 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;
&amp;lt;u&amp;gt;Attention&amp;lt;/u&amp;gt; dans le cas où vous utilisez &amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt; : il est conseillé de terminer votre filtrage avec un motif universel pour être sûr que vous n&#039;avez pas oublié de cas.&lt;br /&gt;
# 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;
&lt;br /&gt;
=== Transparence référentielle ===&lt;br /&gt;
&lt;br /&gt;
=== Les types algébriques ===&lt;br /&gt;
&lt;br /&gt;
On peut défnir un synomnyme de type avec le mot clef &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
Exemple : &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type point = float*float&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Types énumérés ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On donne tous les éléments du type&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type jours = Lundi | Mardi | Mercredi | ...&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Type avec 7 éléments. Les éléments commencent forcément par une majuscule.&lt;br /&gt;
&lt;br /&gt;
On peut comparer des éléments avec &amp;quot;=&amp;quot;, &amp;quot;&amp;lt;&amp;quot; et &amp;quot;&amp;gt;&amp;quot; (&amp;lt; et &amp;gt; sont à éviter, il vaut mieux&lt;br /&gt;
écrire une fonction pour comparer) On peut aussi faire du filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let week_end j = match j with&lt;br /&gt;
Samedi -&amp;gt; true&lt;br /&gt;
   | Dimanche -&amp;gt; true&lt;br /&gt;
   | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Construction de types paramètres ====&lt;br /&gt;
 &lt;br /&gt;
Exemple : type des transformations de l&#039;espace avec :&lt;br /&gt;
- Translation&lt;br /&gt;
- Rotation&lt;br /&gt;
- Symetrie&lt;br /&gt;
On aura alors des constructeurs avec des paramètres :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type transformation =&lt;br /&gt;
Rotation of int*point&lt;br /&gt;
| Translation of point&lt;br /&gt;
| SymCentrale of point&lt;br /&gt;
| Homothetie of float*point&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On n&#039;a pas donné explicitement tous les éléments, mais on les a donné implicitement.&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rien = Translation (0.0,0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Autre exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let fait quelquechose t=&lt;br /&gt;
match t with&lt;br /&gt;
Rotation(a, (x, y)− &amp;gt; a mod360! = 0&lt;br /&gt;
|T ranslation(x, y)− &amp;gt; x! = 0.0 &amp;amp;&amp;amp; y! = 0.0&lt;br /&gt;
|SymCentrale(x, y)− &amp;gt; true&lt;br /&gt;
|Homotetie(x, (−, −))− &amp;gt; r! = 1, 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Les types récursifs ====&lt;br /&gt;
&lt;br /&gt;
En Caml&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type node = Node of int*node&lt;br /&gt;
| Vide&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
exemple d&#039;éléments de &amp;quot;node&amp;quot; :&lt;br /&gt;
- Vide&lt;br /&gt;
- Node(0,Vide)&lt;br /&gt;
- Node(1,Node(2,Node(3, Vide)))&lt;br /&gt;
&lt;br /&gt;
Le type &amp;quot;node&amp;quot; est un type récursif. Comme les fonctions récursivent doivent avoir des cas&lt;br /&gt;
de base, les types récursifs doivent avoir des constructeurs &amp;quot;de base&amp;quot; (non récursifs). On peut&lt;br /&gt;
comparer des éléments avec &amp;quot;=&amp;quot;. On peut aussi utiliser le filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
Vide -&amp;gt; 0&lt;br /&gt;
|Node(_,l)-&amp;gt;1+taille l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction taille sur les listes Caml suit le même schéma avec les abréviations Caml.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
| a ::l-&amp;gt;1+taille&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ceci explique la différence entre :: (constructeur) et @ (fonction récursive)&lt;br /&gt;
&lt;br /&gt;
Exemple de type récursif, les arbres binaires :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type bin = Vide | Noeud of int*bin*bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
arbre naire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type arbre n_aire = &lt;br /&gt;
Vide|Node of int ∗ (arbre_naire list)(bancal)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Les structures ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== La récursivité terminale ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les exceptions ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Aspects impératifs dans Caml ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les modules ==&lt;/div&gt;</summary>
		<author><name>Lachand</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO421_:_Programmation_fonctionnelle&amp;diff=5928</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=5928"/>
		<updated>2013-02-12T18:36:50Z</updated>

		<summary type="html">&lt;p&gt;Lachand : /* Les types récursifs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-421 : 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;
== Détails techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Compléments de cours, TD et TP ===&lt;br /&gt;
&lt;br /&gt;
==== Installer 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;
* Sous MacOS : il semblerait qu&#039;il y ait des paquets MacPorts pour &amp;lt;tt&amp;gt;ocaml&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;emacs&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;tuareg-mode.el&amp;lt;/tt&amp;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;
Pour les exemples simples, vous pouvez aussi utiliser [http://try.ocamlpro.com/ OCaml en ligne]&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;
* 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;
* Le livre de Jason Hickey [http://files.metaprl.org/doc/ocaml-book.pdf Introduction to Objective Caml] (en anglais).&lt;br /&gt;
&lt;br /&gt;
==== Cours ====&lt;br /&gt;
&lt;br /&gt;
==== TD et TP ====&lt;br /&gt;
&lt;br /&gt;
* [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/1213/info421/td1.pdf TD1 : premières expressions en Caml (pdf)]&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;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Attention :&#039;&#039; il ne s&#039;agit pas d&#039;un cours de programmation fonctionelle&lt;br /&gt;
	&amp;lt;/blockquote&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;
=== 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;
* année &#039;80 : Caml (1987), puis CamlLight(1990), puis OCaml(1996), développé&lt;br /&gt;
à l&#039;INRIA. (Dernière version en octobre 2012.)&lt;br /&gt;
* années &#039;90 : Python (version 1.0 en 1994).&lt;br /&gt;
* années &#039;90 : PHP (version 1.0 en 1995).&lt;br /&gt;
* années &#039;90 : Java (version 1.0 en 1996).&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;
&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;&#039;impératifs&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un des slogans de la programmation fonctionnelle en général est&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;&amp;lt;u&amp;gt;Les fonctions sont des valeurs comme les autres&amp;lt;/u&amp;gt;&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
et c&#039;est de là que vient la terminologie... En particulier, il n&#039;y a pas de différence entre les &#039;&#039;instructions&#039;&#039; (qui ont un effet) et les &#039;&#039;expressions&#039;&#039; (qui ont une valeur). Par exemple, en Python,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
x = x+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ou&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if delta &amp;lt; 0:&lt;br /&gt;
    print(&amp;quot;Il n&#039;y a pas de solution&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sont des &#039;&#039;instructions&#039;&#039; : on ne peut pas les mettre dans une variable.&lt;br /&gt;
&lt;br /&gt;
Comme nous le verront, cela a des 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), statiquement typé (nous verrons ce que cela veut dire) qui supporte plusieurs styles de programmation :&lt;br /&gt;
&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 principalement le style fonctionnel, et un peu le style impératif en fin de semestre.&lt;br /&gt;
&lt;br /&gt;
Voici quelques aspects importants du langages que nous essayeront d&#039;aborder pendant le cours :&lt;br /&gt;
&lt;br /&gt;
* fonctions comme valeurs,&lt;br /&gt;
* types de données &#039;&#039;algébriques&#039;&#039;&lt;br /&gt;
* polymorphisme,&lt;br /&gt;
* système d&#039;exceptions,&lt;br /&gt;
* support pour des références et des données mutables (programmation « impure »),&lt;br /&gt;
* système de modules et de foncteurs,&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;récursivité&#039;&#039; sera fondamentale pendant toute la durée du cours...&lt;br /&gt;
&lt;br /&gt;
Un aspect intéressant du langage est que c&#039;est :&lt;br /&gt;
&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;
=== Autres langages fonctionnels ===&lt;br /&gt;
&lt;br /&gt;
Il existe de nombreux autres langages fonctionnels. Par exemple :&lt;br /&gt;
&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;
** Common LISP : [http://en.wikipedia.org/wiki/Common_LISP Wikipedia],&lt;br /&gt;
** Scheme : [http://en.wikipedia.org/wiki/Scheme_%28programming_language%29 Wikipedia].&lt;br /&gt;
* Haskell : [http://en.wikipedia.org/wiki/Haskell_%28programming_language%29 Wikipedia] (inspiré en grande partie de [http://en.wikipedia.org/wiki/Miranda_%28programming_language%29 Miranda]).&lt;br /&gt;
&lt;br /&gt;
Plusieurs langages impératifs intègrent maintenant des aspects propres des langages fonctionnels : Python, Scala, ...&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;
&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;
* analyse de programmes critiques : [http://www.astree.ens.fr/ Astrée],&lt;br /&gt;
* informatique financiere : [http://www.janestreet.com Janestreet Capital] et [http://www.lexifi.com Lexifi].&lt;br /&gt;
&lt;br /&gt;
La viabilité du paradigme fonctionnel se retrouve également dans le langage Erlang ([http://fr.wikipedia.org/wiki/Erlang_%28langage%29 Wikipedia]), un langage fonctionnel développé par Ericsson pour la programmation concurrente de systèmes temps réels.&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, les types algébriques 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;
# 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;
Un des slogans de la programmation fonctionnelle est &#039;&#039;tout est une valeur, ou plus précisément,&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Toute expression &amp;lt;u&amp;gt;a&amp;lt;/u&amp;gt; une valeur.&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette idée n&#039;est pas présente en Python 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: a=12 else: a=13&amp;lt;/tt&amp;gt;&amp;quot; par exemple). En Python, les instructions sont en général séparées par des retours à la ligne 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;
&lt;br /&gt;
* les fonctions du langage (addition, multiplication, opérateurs logiques),&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;
* les relations mathématiques (égalité, plus grand), ... qui sont juste des fonctions renvoyant des booléens,&lt;br /&gt;
* les constantes du langage,&lt;br /&gt;
* les variables de l&#039;environnement,&lt;br /&gt;
* &#039;&#039;les valeurs (en particulier les fonctions) définies par le programmeur&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Bien entendu, comme Caml est typé, il faut respecter 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;
&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;) et les opérations &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt; (et) et &amp;lt;tt&amp;gt;||&amp;lt;/tt&amp;gt; (ou).&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&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;&amp;lt;/math&amp;gt; et &amp;lt;math&amp;gt;2&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;-1&amp;lt;/math&amp;gt;. (Les entiers Caml sont stockés sur 31 bits...) Les opérations associés sont &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; (pour la division entière) et &amp;lt;tt&amp;gt;mod&amp;lt;/tt&amp;gt; (pour le modulo).&lt;br /&gt;
* Les flottants : type &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; pour les réels en virgule flottante. Les opérations usuelles sont &amp;lt;tt&amp;gt;+.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*.&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;/.&amp;lt;/tt&amp;gt;.&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;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* exemples ... *)&lt;br /&gt;
&amp;lt;/source&amp;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écessaire. 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;
=== définitions et 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;, ...&lt;br /&gt;
&lt;br /&gt;
Certaines des variables de l&#039;environnement correspondent à des paramètres de fonction en cours de définition. Ces variables n&#039;ont pas de valeur, mais seulement un type.&lt;br /&gt;
&lt;br /&gt;
==== Environnement ====&lt;br /&gt;
&lt;br /&gt;
* Liste de paires &amp;lt;tt&amp;gt;nom&amp;lt;/tt&amp;gt; / &amp;lt;tt&amp;gt;valeur&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* une nouvelle definition remplace la précédente mais ne l&#039;efface pas, (on ne met pas une valeur à jours)&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;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;let nom = expr&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 nom1 = expr1 and nom2 = expr2&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 nom1 = expr1 and nom2 = expr2&amp;lt;/tt&amp;gt; permet de rajouter des définitions mutuellement récursives.&lt;br /&gt;
&lt;br /&gt;
On peut toujours 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;
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;
&lt;br /&gt;
* : float = 3.1415&lt;br /&gt;
&amp;lt;/source&amp;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 nom = expr1 in expr2&amp;lt;/tt&amp;gt;. Ceci ajoute la définition &amp;lt;tt&amp;gt;nom = expr1&amp;lt;/tt&amp;gt; dans l&#039;environnement, mais seulement pour l&#039;évaluation de l&#039;expression &amp;lt;tt&amp;gt;expr2&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;
&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 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 dont 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;interprète Caml :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # String.length ;;&lt;br /&gt;
&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 fonction est définie comme une variable avec un &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt; et en utilisant le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f = fun n -&amp;gt; n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine = fun n -&amp;gt; int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Une fonction avec plusieurs argument est définie de la même manière avec&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let moyenne3 = fun x y z -&amp;gt; (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le type d&#039;une fonction à plusieurs argument est noté en mettant plusieurs types à gauche de la flèche &amp;lt;tt&amp;gt;-&amp;gt;&amp;lt;/tt&amp;gt;, comme ci dessus : &amp;lt;tt&amp;gt;type_arg1 -&amp;gt; type_arg2 -&amp;gt; type_arg3 -&amp;gt; type_resultat&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarques :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* notez l&#039;absence de mot clé &amp;lt;tt&amp;gt;return&amp;lt;/tt&amp;gt; et l&#039;absence de virgules pour séparer les différents arguments !&lt;br /&gt;
* Le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; permet de définir des fonctions sans leur donner de nom, ce qui n&#039;est pas possible dans les langages comme C ou Java...&lt;br /&gt;
&lt;br /&gt;
On peut également utiliser un raccourci pour définir une fonction sans utiliser le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; : il suffit de mettre les arguments de la fonction avant le signe égal :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f n = n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine n = int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let moyenne3 x y z = (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour appliquer une fonction à des arguments, on écrit simplement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Il n&#039;y a ni parenthèse, ni virgule. Les parenthèses peuvent cependant être nécessaires pour différencier&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 (-0.333 *. 6.)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
et&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(moyenne3 13.5 17.0 -0.333) *. 6.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ou pour que Caml lise correctement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 (17.0 -. 12.0) -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Fonctions récursives ====&lt;br /&gt;
&lt;br /&gt;
Si on essaie de définir une fonction récursivement :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let f n = if (n&amp;lt;1) then 0 else n + f (n-1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Caml répond&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
Error: Unbound value f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
car &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; n&#039;est pas présente dans l&#039;environnement.&lt;br /&gt;
&lt;br /&gt;
Pour rajouter &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; comme variable active (sans valeur) et pouvoir faire une définition récursive, il faut utiliser le mot clé &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let rec f n = if (n&amp;lt;1) then 0 else n + f (n-1);;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les définitions locales peuvent elles aussi être récursives (&amp;lt;tt&amp;gt;let rec ... in ...&amp;lt;/tt&amp;gt;) ou 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;
==== fonctions d&#039;ordre supérieur ====&lt;br /&gt;
&lt;br /&gt;
TODO&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;
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;
Contrairement au cas des tuples, 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; 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;
On peut ajouter un élement devant une liste avec l&#039;opérateur &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; et 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;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# 5::[1;2;3;4] ;;&lt;br /&gt;
- : int list = [5; 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; ne dépend pas de la taille des listes mises en jeux. Par contre, la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot; dépend proportionnellement de la taille de son premier argument. Il faut donc toujour privilégier &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; par rapport à &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot;. En particulier, il est en général mauvais de rajouter des élément en fin de liste en utilisant &amp;quot;&amp;lt;tt&amp;gt;l @ [e]&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Filtrage, première partie : tuples et listes ===&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;filtrage&#039;&#039;, aussi appelé &amp;quot;pattern-matching&amp;quot; est un outils clé pour la programmation en Caml. L&#039;idée est de décomposer une valeur en &amp;quot;sous-valeurs&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les tuples ====&lt;br /&gt;
&lt;br /&gt;
Comme une paire est de la forme &amp;lt;tt&amp;gt;(x,y)&amp;lt;/tt&amp;gt;, on peut décomposer une valeur de type &amp;lt;tt&amp;gt;a*b&amp;lt;/tt&amp;gt; en deux sous valeurs. Voici un exemple de syntaxe : le code de la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt; :&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;
&lt;br /&gt;
Pour évaluer &amp;quot;&amp;lt;tt&amp;gt;premier e&amp;lt;/tt&amp;gt;&amp;quot;, Caml regarde le premier argument &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; et essaie de faire coïncider &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 maintenant récupérer la deuxième composante d&#039;un triplet de la manière suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let second3 t = match t with&lt;br /&gt;
    (_, y, _) -&amp;gt; y&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Notez l&#039;utilisation de &amp;quot;&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;&amp;quot; pour donner la position d&#039;une sous-valeur qui ne sert à rien.&lt;br /&gt;
&lt;br /&gt;
Toutes les variables présentes dans le &#039;&#039;motif&#039;&#039; (la partie à gauche de la flèche) se retrouvent dans l&#039;environnement avec pour valeur, la sous-valeur appropriée. &amp;lt;u&amp;gt;Attention,&amp;lt;/u&amp;gt; ces variables ne se retrouvent dans l&#039;environnement que dans la partie droite de la flèche.&lt;br /&gt;
Ces variables remplacent (temporairement) les variables de même nom qui pouvaient se trouver dans l&#039;environnement. Par exemple, la fonction :&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;
est exactement la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les listes ====&lt;br /&gt;
&lt;br /&gt;
On peut décomposer une liste en deux sous-valeurs :&lt;br /&gt;
&lt;br /&gt;
* le premier élément de la liste,&lt;br /&gt;
* la suite de la liste.&lt;br /&gt;
&lt;br /&gt;
Autrement dit, si la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; n&#039;est pas vide, on peut la décomposer en &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt;. Comme il est possible que la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; soit vide, il y a en fait deux manière de décomposer &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (sans aucune sous-valeur),&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt; (avec deux sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
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;
Les différents cas sont séparés par le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
On peut également décomposer une liste en 3 sous-valeurs : le premier élément, le second élément et la suite de la liste. Dans ce cas, il a trois cas pour une liste arbitraire :&lt;br /&gt;
&lt;br /&gt;
* elle est vide &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (aucune sous-valeur),&lt;br /&gt;
* elle ne contient qu&#039;une seul élément &amp;lt;tt&amp;gt;[e]&amp;lt;/tt&amp;gt; (une sous-valeur),&lt;br /&gt;
* elle contient un premier élément, un deuxième élément, et une suite &amp;lt;tt&amp;gt;a::b::q&amp;lt;/tt&amp;gt; (trois sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
On peut par exemple écrire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus l = match l with&lt;br /&gt;
    [] -&amp;gt; false&lt;br /&gt;
  | [a] -&amp;gt; false&lt;br /&gt;
  | a::b::q -&amp;gt; true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme on peut toujours décomposer une valeur en une sous-valeur (la valeur elle même), on peut toujours avoir un motif de la forme &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;. Toutes les valeurs pourront être décomposées de cette manière, et il faut donc que ce motif soit le dernier. (Sinon, les motifs suivants ne servent à rien...) On parle de motif &#039;&#039;universel&#039;&#039;. (On peut utiliser &amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt; comme motif universel.) Par exemple, on peut réecrire l&#039;exemple précédent :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus&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;
==== Compléments ====&lt;br /&gt;
&lt;br /&gt;
# On peut ajouter des constantes dans les motifs. Le motif ne sera utilisé que lorsque la sous-valeur correspondantes a la valeurs correspondante. Par exemple, si on modélise les entiers de Gauss (« entiers complexes ») par des paires d&#039;entiers, on peut définir :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let imaginaire_pur c = match c with&lt;br /&gt;
    (0,0) -&amp;gt; false&lt;br /&gt;
  | (0,_) -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# On peut grouper des motifs différents pour faire la même chose. Il faut que les variables qui apparaissent dans les motifs soient les mêmes, et qu&#039;elles aient le même type :&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 | 2::_::_::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;
# on peut « garder » les motifs&amp;quot; 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;
&amp;lt;u&amp;gt;Attention&amp;lt;/u&amp;gt; dans le cas où vous utilisez &amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt; : il est conseillé de terminer votre filtrage avec un motif universel pour être sûr que vous n&#039;avez pas oublié de cas.&lt;br /&gt;
# 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;
&lt;br /&gt;
=== Transparence référentielle ===&lt;br /&gt;
&lt;br /&gt;
==== Les types algébriques ====&lt;br /&gt;
&lt;br /&gt;
On peut défnir un synomnyme de type avec le mot clef &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
Exemple : &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type point = float*float&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Types énumérés ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On donne tous les éléments du type&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type jours = Lundi | Mardi | Mercredi | ...&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Type avec 7 éléments. Les éléments commencent forcément par une majuscule.&lt;br /&gt;
&lt;br /&gt;
On peut comparer des éléments avec &amp;quot;=&amp;quot;, &amp;quot;&amp;lt;&amp;quot; et &amp;quot;&amp;gt;&amp;quot; (&amp;lt; et &amp;gt; sont à éviter, il vaut mieux&lt;br /&gt;
écrire une fonction pour comparer) On peut aussi faire du filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let week_end j = match j with&lt;br /&gt;
Samedi -&amp;gt; true&lt;br /&gt;
   | Dimanche -&amp;gt; true&lt;br /&gt;
   | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Construction de types paramètres ====&lt;br /&gt;
 &lt;br /&gt;
Exemple : type des transformations de l&#039;espace avec :&lt;br /&gt;
- Translation&lt;br /&gt;
- Rotation&lt;br /&gt;
- Symetrie&lt;br /&gt;
On aura alors des constructeurs avec des paramètres :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type transformation =&lt;br /&gt;
Rotation of int*point&lt;br /&gt;
| Translation of point&lt;br /&gt;
| SymCentrale of point&lt;br /&gt;
| Homothetie of float*point&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On n&#039;a pas donné explicitement tous les éléments, mais on les a donné implicitement.&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rien = Translation (0.0,0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Autre exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let fait quelquechose t=&lt;br /&gt;
match t with&lt;br /&gt;
Rotation(a, (x, y)− &amp;gt; a mod360! = 0&lt;br /&gt;
|T ranslation(x, y)− &amp;gt; x! = 0.0 &amp;amp;&amp;amp; y! = 0.0&lt;br /&gt;
|SymCentrale(x, y)− &amp;gt; true&lt;br /&gt;
|Homotetie(x, (−, −))− &amp;gt; r! = 1, 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Les types récursifs ====&lt;br /&gt;
&lt;br /&gt;
En Caml&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type node = Node of int*node&lt;br /&gt;
| Vide&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
exemple d&#039;éléments de &amp;quot;node&amp;quot; :&lt;br /&gt;
- Vide&lt;br /&gt;
- Node(0,Vide)&lt;br /&gt;
- Node(1,Node(2,Node(3, Vide)))&lt;br /&gt;
&lt;br /&gt;
Le type &amp;quot;node&amp;quot; est un type récursif. Comme les fonctions récursivent doivent avoir des cas&lt;br /&gt;
de base, les types récursifs doivent avoir des constructeurs &amp;quot;de base&amp;quot; (non récursifs). On peut&lt;br /&gt;
comparer des éléments avec &amp;quot;=&amp;quot;. On peut aussi utiliser le filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
Vide -&amp;gt; 0&lt;br /&gt;
|Node(_,l)-&amp;gt;1+taille l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction taille sur les listes Caml suit le même schéma avec les abréviations Caml.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
| a ::l-&amp;gt;1+taille&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ceci explique la différence entre :: (constructeur) et @ (fonction récursive)&lt;br /&gt;
&lt;br /&gt;
Exemple de type récursif, les arbres binaires :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type bin = Vide | Noeud of int*bin*bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
arbre naire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type arbre n_aire = &lt;br /&gt;
Vide|Node of int ∗ (arbre_naire list)(bancal)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Les structures ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== La récursivité terminale ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les exceptions ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Aspects impératifs dans Caml ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les modules ==&lt;/div&gt;</summary>
		<author><name>Lachand</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO421_:_Programmation_fonctionnelle&amp;diff=5927</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=5927"/>
		<updated>2013-02-12T18:36:41Z</updated>

		<summary type="html">&lt;p&gt;Lachand : /* Construction de types paramètres */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-421 : 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;
== Détails techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Compléments de cours, TD et TP ===&lt;br /&gt;
&lt;br /&gt;
==== Installer 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;
* Sous MacOS : il semblerait qu&#039;il y ait des paquets MacPorts pour &amp;lt;tt&amp;gt;ocaml&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;emacs&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;tuareg-mode.el&amp;lt;/tt&amp;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;
Pour les exemples simples, vous pouvez aussi utiliser [http://try.ocamlpro.com/ OCaml en ligne]&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;
* 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;
* Le livre de Jason Hickey [http://files.metaprl.org/doc/ocaml-book.pdf Introduction to Objective Caml] (en anglais).&lt;br /&gt;
&lt;br /&gt;
==== Cours ====&lt;br /&gt;
&lt;br /&gt;
==== TD et TP ====&lt;br /&gt;
&lt;br /&gt;
* [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/1213/info421/td1.pdf TD1 : premières expressions en Caml (pdf)]&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;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Attention :&#039;&#039; il ne s&#039;agit pas d&#039;un cours de programmation fonctionelle&lt;br /&gt;
	&amp;lt;/blockquote&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;
=== 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;
* année &#039;80 : Caml (1987), puis CamlLight(1990), puis OCaml(1996), développé&lt;br /&gt;
à l&#039;INRIA. (Dernière version en octobre 2012.)&lt;br /&gt;
* années &#039;90 : Python (version 1.0 en 1994).&lt;br /&gt;
* années &#039;90 : PHP (version 1.0 en 1995).&lt;br /&gt;
* années &#039;90 : Java (version 1.0 en 1996).&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;
&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;&#039;impératifs&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un des slogans de la programmation fonctionnelle en général est&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;&amp;lt;u&amp;gt;Les fonctions sont des valeurs comme les autres&amp;lt;/u&amp;gt;&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
et c&#039;est de là que vient la terminologie... En particulier, il n&#039;y a pas de différence entre les &#039;&#039;instructions&#039;&#039; (qui ont un effet) et les &#039;&#039;expressions&#039;&#039; (qui ont une valeur). Par exemple, en Python,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
x = x+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ou&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if delta &amp;lt; 0:&lt;br /&gt;
    print(&amp;quot;Il n&#039;y a pas de solution&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sont des &#039;&#039;instructions&#039;&#039; : on ne peut pas les mettre dans une variable.&lt;br /&gt;
&lt;br /&gt;
Comme nous le verront, cela a des 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), statiquement typé (nous verrons ce que cela veut dire) qui supporte plusieurs styles de programmation :&lt;br /&gt;
&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 principalement le style fonctionnel, et un peu le style impératif en fin de semestre.&lt;br /&gt;
&lt;br /&gt;
Voici quelques aspects importants du langages que nous essayeront d&#039;aborder pendant le cours :&lt;br /&gt;
&lt;br /&gt;
* fonctions comme valeurs,&lt;br /&gt;
* types de données &#039;&#039;algébriques&#039;&#039;&lt;br /&gt;
* polymorphisme,&lt;br /&gt;
* système d&#039;exceptions,&lt;br /&gt;
* support pour des références et des données mutables (programmation « impure »),&lt;br /&gt;
* système de modules et de foncteurs,&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;récursivité&#039;&#039; sera fondamentale pendant toute la durée du cours...&lt;br /&gt;
&lt;br /&gt;
Un aspect intéressant du langage est que c&#039;est :&lt;br /&gt;
&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;
=== Autres langages fonctionnels ===&lt;br /&gt;
&lt;br /&gt;
Il existe de nombreux autres langages fonctionnels. Par exemple :&lt;br /&gt;
&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;
** Common LISP : [http://en.wikipedia.org/wiki/Common_LISP Wikipedia],&lt;br /&gt;
** Scheme : [http://en.wikipedia.org/wiki/Scheme_%28programming_language%29 Wikipedia].&lt;br /&gt;
* Haskell : [http://en.wikipedia.org/wiki/Haskell_%28programming_language%29 Wikipedia] (inspiré en grande partie de [http://en.wikipedia.org/wiki/Miranda_%28programming_language%29 Miranda]).&lt;br /&gt;
&lt;br /&gt;
Plusieurs langages impératifs intègrent maintenant des aspects propres des langages fonctionnels : Python, Scala, ...&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;
&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;
* analyse de programmes critiques : [http://www.astree.ens.fr/ Astrée],&lt;br /&gt;
* informatique financiere : [http://www.janestreet.com Janestreet Capital] et [http://www.lexifi.com Lexifi].&lt;br /&gt;
&lt;br /&gt;
La viabilité du paradigme fonctionnel se retrouve également dans le langage Erlang ([http://fr.wikipedia.org/wiki/Erlang_%28langage%29 Wikipedia]), un langage fonctionnel développé par Ericsson pour la programmation concurrente de systèmes temps réels.&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, les types algébriques 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;
# 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;
Un des slogans de la programmation fonctionnelle est &#039;&#039;tout est une valeur, ou plus précisément,&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Toute expression &amp;lt;u&amp;gt;a&amp;lt;/u&amp;gt; une valeur.&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette idée n&#039;est pas présente en Python 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: a=12 else: a=13&amp;lt;/tt&amp;gt;&amp;quot; par exemple). En Python, les instructions sont en général séparées par des retours à la ligne 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;
&lt;br /&gt;
* les fonctions du langage (addition, multiplication, opérateurs logiques),&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;
* les relations mathématiques (égalité, plus grand), ... qui sont juste des fonctions renvoyant des booléens,&lt;br /&gt;
* les constantes du langage,&lt;br /&gt;
* les variables de l&#039;environnement,&lt;br /&gt;
* &#039;&#039;les valeurs (en particulier les fonctions) définies par le programmeur&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Bien entendu, comme Caml est typé, il faut respecter 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;
&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;) et les opérations &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt; (et) et &amp;lt;tt&amp;gt;||&amp;lt;/tt&amp;gt; (ou).&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&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;&amp;lt;/math&amp;gt; et &amp;lt;math&amp;gt;2&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;-1&amp;lt;/math&amp;gt;. (Les entiers Caml sont stockés sur 31 bits...) Les opérations associés sont &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; (pour la division entière) et &amp;lt;tt&amp;gt;mod&amp;lt;/tt&amp;gt; (pour le modulo).&lt;br /&gt;
* Les flottants : type &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; pour les réels en virgule flottante. Les opérations usuelles sont &amp;lt;tt&amp;gt;+.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*.&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;/.&amp;lt;/tt&amp;gt;.&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;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* exemples ... *)&lt;br /&gt;
&amp;lt;/source&amp;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écessaire. 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;
=== définitions et 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;, ...&lt;br /&gt;
&lt;br /&gt;
Certaines des variables de l&#039;environnement correspondent à des paramètres de fonction en cours de définition. Ces variables n&#039;ont pas de valeur, mais seulement un type.&lt;br /&gt;
&lt;br /&gt;
==== Environnement ====&lt;br /&gt;
&lt;br /&gt;
* Liste de paires &amp;lt;tt&amp;gt;nom&amp;lt;/tt&amp;gt; / &amp;lt;tt&amp;gt;valeur&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* une nouvelle definition remplace la précédente mais ne l&#039;efface pas, (on ne met pas une valeur à jours)&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;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;let nom = expr&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 nom1 = expr1 and nom2 = expr2&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 nom1 = expr1 and nom2 = expr2&amp;lt;/tt&amp;gt; permet de rajouter des définitions mutuellement récursives.&lt;br /&gt;
&lt;br /&gt;
On peut toujours 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;
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;
&lt;br /&gt;
* : float = 3.1415&lt;br /&gt;
&amp;lt;/source&amp;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 nom = expr1 in expr2&amp;lt;/tt&amp;gt;. Ceci ajoute la définition &amp;lt;tt&amp;gt;nom = expr1&amp;lt;/tt&amp;gt; dans l&#039;environnement, mais seulement pour l&#039;évaluation de l&#039;expression &amp;lt;tt&amp;gt;expr2&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;
&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 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 dont 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;interprète Caml :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # String.length ;;&lt;br /&gt;
&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 fonction est définie comme une variable avec un &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt; et en utilisant le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f = fun n -&amp;gt; n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine = fun n -&amp;gt; int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Une fonction avec plusieurs argument est définie de la même manière avec&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let moyenne3 = fun x y z -&amp;gt; (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le type d&#039;une fonction à plusieurs argument est noté en mettant plusieurs types à gauche de la flèche &amp;lt;tt&amp;gt;-&amp;gt;&amp;lt;/tt&amp;gt;, comme ci dessus : &amp;lt;tt&amp;gt;type_arg1 -&amp;gt; type_arg2 -&amp;gt; type_arg3 -&amp;gt; type_resultat&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarques :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* notez l&#039;absence de mot clé &amp;lt;tt&amp;gt;return&amp;lt;/tt&amp;gt; et l&#039;absence de virgules pour séparer les différents arguments !&lt;br /&gt;
* Le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; permet de définir des fonctions sans leur donner de nom, ce qui n&#039;est pas possible dans les langages comme C ou Java...&lt;br /&gt;
&lt;br /&gt;
On peut également utiliser un raccourci pour définir une fonction sans utiliser le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; : il suffit de mettre les arguments de la fonction avant le signe égal :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f n = n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine n = int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let moyenne3 x y z = (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour appliquer une fonction à des arguments, on écrit simplement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Il n&#039;y a ni parenthèse, ni virgule. Les parenthèses peuvent cependant être nécessaires pour différencier&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 (-0.333 *. 6.)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
et&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(moyenne3 13.5 17.0 -0.333) *. 6.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ou pour que Caml lise correctement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 (17.0 -. 12.0) -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Fonctions récursives ====&lt;br /&gt;
&lt;br /&gt;
Si on essaie de définir une fonction récursivement :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let f n = if (n&amp;lt;1) then 0 else n + f (n-1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Caml répond&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
Error: Unbound value f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
car &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; n&#039;est pas présente dans l&#039;environnement.&lt;br /&gt;
&lt;br /&gt;
Pour rajouter &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; comme variable active (sans valeur) et pouvoir faire une définition récursive, il faut utiliser le mot clé &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let rec f n = if (n&amp;lt;1) then 0 else n + f (n-1);;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les définitions locales peuvent elles aussi être récursives (&amp;lt;tt&amp;gt;let rec ... in ...&amp;lt;/tt&amp;gt;) ou 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;
==== fonctions d&#039;ordre supérieur ====&lt;br /&gt;
&lt;br /&gt;
TODO&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;
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;
Contrairement au cas des tuples, 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; 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;
On peut ajouter un élement devant une liste avec l&#039;opérateur &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; et 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;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# 5::[1;2;3;4] ;;&lt;br /&gt;
- : int list = [5; 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; ne dépend pas de la taille des listes mises en jeux. Par contre, la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot; dépend proportionnellement de la taille de son premier argument. Il faut donc toujour privilégier &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; par rapport à &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot;. En particulier, il est en général mauvais de rajouter des élément en fin de liste en utilisant &amp;quot;&amp;lt;tt&amp;gt;l @ [e]&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Filtrage, première partie : tuples et listes ===&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;filtrage&#039;&#039;, aussi appelé &amp;quot;pattern-matching&amp;quot; est un outils clé pour la programmation en Caml. L&#039;idée est de décomposer une valeur en &amp;quot;sous-valeurs&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les tuples ====&lt;br /&gt;
&lt;br /&gt;
Comme une paire est de la forme &amp;lt;tt&amp;gt;(x,y)&amp;lt;/tt&amp;gt;, on peut décomposer une valeur de type &amp;lt;tt&amp;gt;a*b&amp;lt;/tt&amp;gt; en deux sous valeurs. Voici un exemple de syntaxe : le code de la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt; :&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;
&lt;br /&gt;
Pour évaluer &amp;quot;&amp;lt;tt&amp;gt;premier e&amp;lt;/tt&amp;gt;&amp;quot;, Caml regarde le premier argument &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; et essaie de faire coïncider &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 maintenant récupérer la deuxième composante d&#039;un triplet de la manière suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let second3 t = match t with&lt;br /&gt;
    (_, y, _) -&amp;gt; y&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Notez l&#039;utilisation de &amp;quot;&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;&amp;quot; pour donner la position d&#039;une sous-valeur qui ne sert à rien.&lt;br /&gt;
&lt;br /&gt;
Toutes les variables présentes dans le &#039;&#039;motif&#039;&#039; (la partie à gauche de la flèche) se retrouvent dans l&#039;environnement avec pour valeur, la sous-valeur appropriée. &amp;lt;u&amp;gt;Attention,&amp;lt;/u&amp;gt; ces variables ne se retrouvent dans l&#039;environnement que dans la partie droite de la flèche.&lt;br /&gt;
Ces variables remplacent (temporairement) les variables de même nom qui pouvaient se trouver dans l&#039;environnement. Par exemple, la fonction :&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;
est exactement la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les listes ====&lt;br /&gt;
&lt;br /&gt;
On peut décomposer une liste en deux sous-valeurs :&lt;br /&gt;
&lt;br /&gt;
* le premier élément de la liste,&lt;br /&gt;
* la suite de la liste.&lt;br /&gt;
&lt;br /&gt;
Autrement dit, si la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; n&#039;est pas vide, on peut la décomposer en &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt;. Comme il est possible que la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; soit vide, il y a en fait deux manière de décomposer &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (sans aucune sous-valeur),&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt; (avec deux sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
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;
Les différents cas sont séparés par le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
On peut également décomposer une liste en 3 sous-valeurs : le premier élément, le second élément et la suite de la liste. Dans ce cas, il a trois cas pour une liste arbitraire :&lt;br /&gt;
&lt;br /&gt;
* elle est vide &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (aucune sous-valeur),&lt;br /&gt;
* elle ne contient qu&#039;une seul élément &amp;lt;tt&amp;gt;[e]&amp;lt;/tt&amp;gt; (une sous-valeur),&lt;br /&gt;
* elle contient un premier élément, un deuxième élément, et une suite &amp;lt;tt&amp;gt;a::b::q&amp;lt;/tt&amp;gt; (trois sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
On peut par exemple écrire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus l = match l with&lt;br /&gt;
    [] -&amp;gt; false&lt;br /&gt;
  | [a] -&amp;gt; false&lt;br /&gt;
  | a::b::q -&amp;gt; true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme on peut toujours décomposer une valeur en une sous-valeur (la valeur elle même), on peut toujours avoir un motif de la forme &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;. Toutes les valeurs pourront être décomposées de cette manière, et il faut donc que ce motif soit le dernier. (Sinon, les motifs suivants ne servent à rien...) On parle de motif &#039;&#039;universel&#039;&#039;. (On peut utiliser &amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt; comme motif universel.) Par exemple, on peut réecrire l&#039;exemple précédent :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus&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;
==== Compléments ====&lt;br /&gt;
&lt;br /&gt;
# On peut ajouter des constantes dans les motifs. Le motif ne sera utilisé que lorsque la sous-valeur correspondantes a la valeurs correspondante. Par exemple, si on modélise les entiers de Gauss (« entiers complexes ») par des paires d&#039;entiers, on peut définir :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let imaginaire_pur c = match c with&lt;br /&gt;
    (0,0) -&amp;gt; false&lt;br /&gt;
  | (0,_) -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# On peut grouper des motifs différents pour faire la même chose. Il faut que les variables qui apparaissent dans les motifs soient les mêmes, et qu&#039;elles aient le même type :&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 | 2::_::_::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;
# on peut « garder » les motifs&amp;quot; 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;
&amp;lt;u&amp;gt;Attention&amp;lt;/u&amp;gt; dans le cas où vous utilisez &amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt; : il est conseillé de terminer votre filtrage avec un motif universel pour être sûr que vous n&#039;avez pas oublié de cas.&lt;br /&gt;
# 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;
&lt;br /&gt;
=== Transparence référentielle ===&lt;br /&gt;
&lt;br /&gt;
==== Les types algébriques ====&lt;br /&gt;
&lt;br /&gt;
On peut défnir un synomnyme de type avec le mot clef &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
Exemple : &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type point = float*float&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Types énumérés ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On donne tous les éléments du type&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type jours = Lundi | Mardi | Mercredi | ...&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Type avec 7 éléments. Les éléments commencent forcément par une majuscule.&lt;br /&gt;
&lt;br /&gt;
On peut comparer des éléments avec &amp;quot;=&amp;quot;, &amp;quot;&amp;lt;&amp;quot; et &amp;quot;&amp;gt;&amp;quot; (&amp;lt; et &amp;gt; sont à éviter, il vaut mieux&lt;br /&gt;
écrire une fonction pour comparer) On peut aussi faire du filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let week_end j = match j with&lt;br /&gt;
Samedi -&amp;gt; true&lt;br /&gt;
   | Dimanche -&amp;gt; true&lt;br /&gt;
   | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Construction de types paramètres ====&lt;br /&gt;
 &lt;br /&gt;
Exemple : type des transformations de l&#039;espace avec :&lt;br /&gt;
- Translation&lt;br /&gt;
- Rotation&lt;br /&gt;
- Symetrie&lt;br /&gt;
On aura alors des constructeurs avec des paramètres :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type transformation =&lt;br /&gt;
Rotation of int*point&lt;br /&gt;
| Translation of point&lt;br /&gt;
| SymCentrale of point&lt;br /&gt;
| Homothetie of float*point&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On n&#039;a pas donné explicitement tous les éléments, mais on les a donné implicitement.&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rien = Translation (0.0,0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Autre exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let fait quelquechose t=&lt;br /&gt;
match t with&lt;br /&gt;
Rotation(a, (x, y)− &amp;gt; a mod360! = 0&lt;br /&gt;
|T ranslation(x, y)− &amp;gt; x! = 0.0 &amp;amp;&amp;amp; y! = 0.0&lt;br /&gt;
|SymCentrale(x, y)− &amp;gt; true&lt;br /&gt;
|Homotetie(x, (−, −))− &amp;gt; r! = 1, 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Les types récursifs ===&lt;br /&gt;
&lt;br /&gt;
En Caml&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type node = Node of int*node&lt;br /&gt;
| Vide&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
exemple d&#039;éléments de &amp;quot;node&amp;quot; :&lt;br /&gt;
- Vide&lt;br /&gt;
- Node(0,Vide)&lt;br /&gt;
- Node(1,Node(2,Node(3, Vide)))&lt;br /&gt;
&lt;br /&gt;
Le type &amp;quot;node&amp;quot; est un type récursif. Comme les fonctions récursivent doivent avoir des cas&lt;br /&gt;
de base, les types récursifs doivent avoir des constructeurs &amp;quot;de base&amp;quot; (non récursifs). On peut&lt;br /&gt;
comparer des éléments avec &amp;quot;=&amp;quot;. On peut aussi utiliser le filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
Vide -&amp;gt; 0&lt;br /&gt;
|Node(_,l)-&amp;gt;1+taille l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction taille sur les listes Caml suit le même schéma avec les abréviations Caml.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
| a ::l-&amp;gt;1+taille&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ceci explique la différence entre :: (constructeur) et @ (fonction récursive)&lt;br /&gt;
&lt;br /&gt;
Exemple de type récursif, les arbres binaires :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type bin = Vide | Noeud of int*bin*bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
arbre naire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type arbre n_aire = &lt;br /&gt;
Vide|Node of int ∗ (arbre_naire list)(bancal)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Les structures ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== La récursivité terminale ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les exceptions ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Aspects impératifs dans Caml ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les modules ==&lt;/div&gt;</summary>
		<author><name>Lachand</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO421_:_Programmation_fonctionnelle&amp;diff=5926</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=5926"/>
		<updated>2013-02-12T18:36:26Z</updated>

		<summary type="html">&lt;p&gt;Lachand : /* Types énumérés */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-421 : 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;
== Détails techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Compléments de cours, TD et TP ===&lt;br /&gt;
&lt;br /&gt;
==== Installer 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;
* Sous MacOS : il semblerait qu&#039;il y ait des paquets MacPorts pour &amp;lt;tt&amp;gt;ocaml&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;emacs&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;tuareg-mode.el&amp;lt;/tt&amp;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;
Pour les exemples simples, vous pouvez aussi utiliser [http://try.ocamlpro.com/ OCaml en ligne]&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;
* 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;
* Le livre de Jason Hickey [http://files.metaprl.org/doc/ocaml-book.pdf Introduction to Objective Caml] (en anglais).&lt;br /&gt;
&lt;br /&gt;
==== Cours ====&lt;br /&gt;
&lt;br /&gt;
==== TD et TP ====&lt;br /&gt;
&lt;br /&gt;
* [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/1213/info421/td1.pdf TD1 : premières expressions en Caml (pdf)]&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;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Attention :&#039;&#039; il ne s&#039;agit pas d&#039;un cours de programmation fonctionelle&lt;br /&gt;
	&amp;lt;/blockquote&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;
=== 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;
* année &#039;80 : Caml (1987), puis CamlLight(1990), puis OCaml(1996), développé&lt;br /&gt;
à l&#039;INRIA. (Dernière version en octobre 2012.)&lt;br /&gt;
* années &#039;90 : Python (version 1.0 en 1994).&lt;br /&gt;
* années &#039;90 : PHP (version 1.0 en 1995).&lt;br /&gt;
* années &#039;90 : Java (version 1.0 en 1996).&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;
&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;&#039;impératifs&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un des slogans de la programmation fonctionnelle en général est&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;&amp;lt;u&amp;gt;Les fonctions sont des valeurs comme les autres&amp;lt;/u&amp;gt;&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
et c&#039;est de là que vient la terminologie... En particulier, il n&#039;y a pas de différence entre les &#039;&#039;instructions&#039;&#039; (qui ont un effet) et les &#039;&#039;expressions&#039;&#039; (qui ont une valeur). Par exemple, en Python,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
x = x+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ou&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if delta &amp;lt; 0:&lt;br /&gt;
    print(&amp;quot;Il n&#039;y a pas de solution&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sont des &#039;&#039;instructions&#039;&#039; : on ne peut pas les mettre dans une variable.&lt;br /&gt;
&lt;br /&gt;
Comme nous le verront, cela a des 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), statiquement typé (nous verrons ce que cela veut dire) qui supporte plusieurs styles de programmation :&lt;br /&gt;
&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 principalement le style fonctionnel, et un peu le style impératif en fin de semestre.&lt;br /&gt;
&lt;br /&gt;
Voici quelques aspects importants du langages que nous essayeront d&#039;aborder pendant le cours :&lt;br /&gt;
&lt;br /&gt;
* fonctions comme valeurs,&lt;br /&gt;
* types de données &#039;&#039;algébriques&#039;&#039;&lt;br /&gt;
* polymorphisme,&lt;br /&gt;
* système d&#039;exceptions,&lt;br /&gt;
* support pour des références et des données mutables (programmation « impure »),&lt;br /&gt;
* système de modules et de foncteurs,&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;récursivité&#039;&#039; sera fondamentale pendant toute la durée du cours...&lt;br /&gt;
&lt;br /&gt;
Un aspect intéressant du langage est que c&#039;est :&lt;br /&gt;
&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;
=== Autres langages fonctionnels ===&lt;br /&gt;
&lt;br /&gt;
Il existe de nombreux autres langages fonctionnels. Par exemple :&lt;br /&gt;
&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;
** Common LISP : [http://en.wikipedia.org/wiki/Common_LISP Wikipedia],&lt;br /&gt;
** Scheme : [http://en.wikipedia.org/wiki/Scheme_%28programming_language%29 Wikipedia].&lt;br /&gt;
* Haskell : [http://en.wikipedia.org/wiki/Haskell_%28programming_language%29 Wikipedia] (inspiré en grande partie de [http://en.wikipedia.org/wiki/Miranda_%28programming_language%29 Miranda]).&lt;br /&gt;
&lt;br /&gt;
Plusieurs langages impératifs intègrent maintenant des aspects propres des langages fonctionnels : Python, Scala, ...&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;
&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;
* analyse de programmes critiques : [http://www.astree.ens.fr/ Astrée],&lt;br /&gt;
* informatique financiere : [http://www.janestreet.com Janestreet Capital] et [http://www.lexifi.com Lexifi].&lt;br /&gt;
&lt;br /&gt;
La viabilité du paradigme fonctionnel se retrouve également dans le langage Erlang ([http://fr.wikipedia.org/wiki/Erlang_%28langage%29 Wikipedia]), un langage fonctionnel développé par Ericsson pour la programmation concurrente de systèmes temps réels.&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, les types algébriques 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;
# 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;
Un des slogans de la programmation fonctionnelle est &#039;&#039;tout est une valeur, ou plus précisément,&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Toute expression &amp;lt;u&amp;gt;a&amp;lt;/u&amp;gt; une valeur.&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette idée n&#039;est pas présente en Python 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: a=12 else: a=13&amp;lt;/tt&amp;gt;&amp;quot; par exemple). En Python, les instructions sont en général séparées par des retours à la ligne 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;
&lt;br /&gt;
* les fonctions du langage (addition, multiplication, opérateurs logiques),&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;
* les relations mathématiques (égalité, plus grand), ... qui sont juste des fonctions renvoyant des booléens,&lt;br /&gt;
* les constantes du langage,&lt;br /&gt;
* les variables de l&#039;environnement,&lt;br /&gt;
* &#039;&#039;les valeurs (en particulier les fonctions) définies par le programmeur&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Bien entendu, comme Caml est typé, il faut respecter 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;
&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;) et les opérations &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt; (et) et &amp;lt;tt&amp;gt;||&amp;lt;/tt&amp;gt; (ou).&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&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;&amp;lt;/math&amp;gt; et &amp;lt;math&amp;gt;2&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;-1&amp;lt;/math&amp;gt;. (Les entiers Caml sont stockés sur 31 bits...) Les opérations associés sont &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; (pour la division entière) et &amp;lt;tt&amp;gt;mod&amp;lt;/tt&amp;gt; (pour le modulo).&lt;br /&gt;
* Les flottants : type &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; pour les réels en virgule flottante. Les opérations usuelles sont &amp;lt;tt&amp;gt;+.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*.&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;/.&amp;lt;/tt&amp;gt;.&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;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* exemples ... *)&lt;br /&gt;
&amp;lt;/source&amp;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écessaire. 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;
=== définitions et 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;, ...&lt;br /&gt;
&lt;br /&gt;
Certaines des variables de l&#039;environnement correspondent à des paramètres de fonction en cours de définition. Ces variables n&#039;ont pas de valeur, mais seulement un type.&lt;br /&gt;
&lt;br /&gt;
==== Environnement ====&lt;br /&gt;
&lt;br /&gt;
* Liste de paires &amp;lt;tt&amp;gt;nom&amp;lt;/tt&amp;gt; / &amp;lt;tt&amp;gt;valeur&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* une nouvelle definition remplace la précédente mais ne l&#039;efface pas, (on ne met pas une valeur à jours)&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;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;let nom = expr&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 nom1 = expr1 and nom2 = expr2&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 nom1 = expr1 and nom2 = expr2&amp;lt;/tt&amp;gt; permet de rajouter des définitions mutuellement récursives.&lt;br /&gt;
&lt;br /&gt;
On peut toujours 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;
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;
&lt;br /&gt;
* : float = 3.1415&lt;br /&gt;
&amp;lt;/source&amp;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 nom = expr1 in expr2&amp;lt;/tt&amp;gt;. Ceci ajoute la définition &amp;lt;tt&amp;gt;nom = expr1&amp;lt;/tt&amp;gt; dans l&#039;environnement, mais seulement pour l&#039;évaluation de l&#039;expression &amp;lt;tt&amp;gt;expr2&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;
&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 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 dont 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;interprète Caml :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # String.length ;;&lt;br /&gt;
&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 fonction est définie comme une variable avec un &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt; et en utilisant le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f = fun n -&amp;gt; n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine = fun n -&amp;gt; int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Une fonction avec plusieurs argument est définie de la même manière avec&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let moyenne3 = fun x y z -&amp;gt; (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le type d&#039;une fonction à plusieurs argument est noté en mettant plusieurs types à gauche de la flèche &amp;lt;tt&amp;gt;-&amp;gt;&amp;lt;/tt&amp;gt;, comme ci dessus : &amp;lt;tt&amp;gt;type_arg1 -&amp;gt; type_arg2 -&amp;gt; type_arg3 -&amp;gt; type_resultat&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarques :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* notez l&#039;absence de mot clé &amp;lt;tt&amp;gt;return&amp;lt;/tt&amp;gt; et l&#039;absence de virgules pour séparer les différents arguments !&lt;br /&gt;
* Le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; permet de définir des fonctions sans leur donner de nom, ce qui n&#039;est pas possible dans les langages comme C ou Java...&lt;br /&gt;
&lt;br /&gt;
On peut également utiliser un raccourci pour définir une fonction sans utiliser le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; : il suffit de mettre les arguments de la fonction avant le signe égal :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f n = n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine n = int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let moyenne3 x y z = (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour appliquer une fonction à des arguments, on écrit simplement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Il n&#039;y a ni parenthèse, ni virgule. Les parenthèses peuvent cependant être nécessaires pour différencier&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 (-0.333 *. 6.)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
et&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(moyenne3 13.5 17.0 -0.333) *. 6.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ou pour que Caml lise correctement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 (17.0 -. 12.0) -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Fonctions récursives ====&lt;br /&gt;
&lt;br /&gt;
Si on essaie de définir une fonction récursivement :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let f n = if (n&amp;lt;1) then 0 else n + f (n-1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Caml répond&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
Error: Unbound value f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
car &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; n&#039;est pas présente dans l&#039;environnement.&lt;br /&gt;
&lt;br /&gt;
Pour rajouter &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; comme variable active (sans valeur) et pouvoir faire une définition récursive, il faut utiliser le mot clé &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let rec f n = if (n&amp;lt;1) then 0 else n + f (n-1);;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les définitions locales peuvent elles aussi être récursives (&amp;lt;tt&amp;gt;let rec ... in ...&amp;lt;/tt&amp;gt;) ou 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;
==== fonctions d&#039;ordre supérieur ====&lt;br /&gt;
&lt;br /&gt;
TODO&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;
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;
Contrairement au cas des tuples, 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; 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;
On peut ajouter un élement devant une liste avec l&#039;opérateur &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; et 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;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# 5::[1;2;3;4] ;;&lt;br /&gt;
- : int list = [5; 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; ne dépend pas de la taille des listes mises en jeux. Par contre, la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot; dépend proportionnellement de la taille de son premier argument. Il faut donc toujour privilégier &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; par rapport à &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot;. En particulier, il est en général mauvais de rajouter des élément en fin de liste en utilisant &amp;quot;&amp;lt;tt&amp;gt;l @ [e]&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Filtrage, première partie : tuples et listes ===&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;filtrage&#039;&#039;, aussi appelé &amp;quot;pattern-matching&amp;quot; est un outils clé pour la programmation en Caml. L&#039;idée est de décomposer une valeur en &amp;quot;sous-valeurs&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les tuples ====&lt;br /&gt;
&lt;br /&gt;
Comme une paire est de la forme &amp;lt;tt&amp;gt;(x,y)&amp;lt;/tt&amp;gt;, on peut décomposer une valeur de type &amp;lt;tt&amp;gt;a*b&amp;lt;/tt&amp;gt; en deux sous valeurs. Voici un exemple de syntaxe : le code de la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt; :&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;
&lt;br /&gt;
Pour évaluer &amp;quot;&amp;lt;tt&amp;gt;premier e&amp;lt;/tt&amp;gt;&amp;quot;, Caml regarde le premier argument &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; et essaie de faire coïncider &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 maintenant récupérer la deuxième composante d&#039;un triplet de la manière suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let second3 t = match t with&lt;br /&gt;
    (_, y, _) -&amp;gt; y&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Notez l&#039;utilisation de &amp;quot;&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;&amp;quot; pour donner la position d&#039;une sous-valeur qui ne sert à rien.&lt;br /&gt;
&lt;br /&gt;
Toutes les variables présentes dans le &#039;&#039;motif&#039;&#039; (la partie à gauche de la flèche) se retrouvent dans l&#039;environnement avec pour valeur, la sous-valeur appropriée. &amp;lt;u&amp;gt;Attention,&amp;lt;/u&amp;gt; ces variables ne se retrouvent dans l&#039;environnement que dans la partie droite de la flèche.&lt;br /&gt;
Ces variables remplacent (temporairement) les variables de même nom qui pouvaient se trouver dans l&#039;environnement. Par exemple, la fonction :&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;
est exactement la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les listes ====&lt;br /&gt;
&lt;br /&gt;
On peut décomposer une liste en deux sous-valeurs :&lt;br /&gt;
&lt;br /&gt;
* le premier élément de la liste,&lt;br /&gt;
* la suite de la liste.&lt;br /&gt;
&lt;br /&gt;
Autrement dit, si la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; n&#039;est pas vide, on peut la décomposer en &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt;. Comme il est possible que la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; soit vide, il y a en fait deux manière de décomposer &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (sans aucune sous-valeur),&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt; (avec deux sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
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;
Les différents cas sont séparés par le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
On peut également décomposer une liste en 3 sous-valeurs : le premier élément, le second élément et la suite de la liste. Dans ce cas, il a trois cas pour une liste arbitraire :&lt;br /&gt;
&lt;br /&gt;
* elle est vide &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (aucune sous-valeur),&lt;br /&gt;
* elle ne contient qu&#039;une seul élément &amp;lt;tt&amp;gt;[e]&amp;lt;/tt&amp;gt; (une sous-valeur),&lt;br /&gt;
* elle contient un premier élément, un deuxième élément, et une suite &amp;lt;tt&amp;gt;a::b::q&amp;lt;/tt&amp;gt; (trois sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
On peut par exemple écrire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus l = match l with&lt;br /&gt;
    [] -&amp;gt; false&lt;br /&gt;
  | [a] -&amp;gt; false&lt;br /&gt;
  | a::b::q -&amp;gt; true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme on peut toujours décomposer une valeur en une sous-valeur (la valeur elle même), on peut toujours avoir un motif de la forme &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;. Toutes les valeurs pourront être décomposées de cette manière, et il faut donc que ce motif soit le dernier. (Sinon, les motifs suivants ne servent à rien...) On parle de motif &#039;&#039;universel&#039;&#039;. (On peut utiliser &amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt; comme motif universel.) Par exemple, on peut réecrire l&#039;exemple précédent :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus&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;
==== Compléments ====&lt;br /&gt;
&lt;br /&gt;
# On peut ajouter des constantes dans les motifs. Le motif ne sera utilisé que lorsque la sous-valeur correspondantes a la valeurs correspondante. Par exemple, si on modélise les entiers de Gauss (« entiers complexes ») par des paires d&#039;entiers, on peut définir :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let imaginaire_pur c = match c with&lt;br /&gt;
    (0,0) -&amp;gt; false&lt;br /&gt;
  | (0,_) -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# On peut grouper des motifs différents pour faire la même chose. Il faut que les variables qui apparaissent dans les motifs soient les mêmes, et qu&#039;elles aient le même type :&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 | 2::_::_::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;
# on peut « garder » les motifs&amp;quot; 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;
&amp;lt;u&amp;gt;Attention&amp;lt;/u&amp;gt; dans le cas où vous utilisez &amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt; : il est conseillé de terminer votre filtrage avec un motif universel pour être sûr que vous n&#039;avez pas oublié de cas.&lt;br /&gt;
# 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;
&lt;br /&gt;
=== Transparence référentielle ===&lt;br /&gt;
&lt;br /&gt;
==== Les types algébriques ====&lt;br /&gt;
&lt;br /&gt;
On peut défnir un synomnyme de type avec le mot clef &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
Exemple : &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type point = float*float&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Types énumérés ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On donne tous les éléments du type&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type jours = Lundi | Mardi | Mercredi | ...&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Type avec 7 éléments. Les éléments commencent forcément par une majuscule.&lt;br /&gt;
&lt;br /&gt;
On peut comparer des éléments avec &amp;quot;=&amp;quot;, &amp;quot;&amp;lt;&amp;quot; et &amp;quot;&amp;gt;&amp;quot; (&amp;lt; et &amp;gt; sont à éviter, il vaut mieux&lt;br /&gt;
écrire une fonction pour comparer) On peut aussi faire du filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let week_end j = match j with&lt;br /&gt;
Samedi -&amp;gt; true&lt;br /&gt;
   | Dimanche -&amp;gt; true&lt;br /&gt;
   | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Construction de types paramètres ===&lt;br /&gt;
 &lt;br /&gt;
Exemple : type des transformations de l&#039;espace avec :&lt;br /&gt;
- Translation&lt;br /&gt;
- Rotation&lt;br /&gt;
- Symetrie&lt;br /&gt;
On aura alors des constructeurs avec des paramètres :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type transformation =&lt;br /&gt;
Rotation of int*point&lt;br /&gt;
| Translation of point&lt;br /&gt;
| SymCentrale of point&lt;br /&gt;
| Homothetie of float*point&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On n&#039;a pas donné explicitement tous les éléments, mais on les a donné implicitement.&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rien = Translation (0.0,0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Autre exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let fait quelquechose t=&lt;br /&gt;
match t with&lt;br /&gt;
Rotation(a, (x, y)− &amp;gt; a mod360! = 0&lt;br /&gt;
|T ranslation(x, y)− &amp;gt; x! = 0.0 &amp;amp;&amp;amp; y! = 0.0&lt;br /&gt;
|SymCentrale(x, y)− &amp;gt; true&lt;br /&gt;
|Homotetie(x, (−, −))− &amp;gt; r! = 1, 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Les types récursifs ===&lt;br /&gt;
&lt;br /&gt;
En Caml&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type node = Node of int*node&lt;br /&gt;
| Vide&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
exemple d&#039;éléments de &amp;quot;node&amp;quot; :&lt;br /&gt;
- Vide&lt;br /&gt;
- Node(0,Vide)&lt;br /&gt;
- Node(1,Node(2,Node(3, Vide)))&lt;br /&gt;
&lt;br /&gt;
Le type &amp;quot;node&amp;quot; est un type récursif. Comme les fonctions récursivent doivent avoir des cas&lt;br /&gt;
de base, les types récursifs doivent avoir des constructeurs &amp;quot;de base&amp;quot; (non récursifs). On peut&lt;br /&gt;
comparer des éléments avec &amp;quot;=&amp;quot;. On peut aussi utiliser le filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
Vide -&amp;gt; 0&lt;br /&gt;
|Node(_,l)-&amp;gt;1+taille l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction taille sur les listes Caml suit le même schéma avec les abréviations Caml.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
| a ::l-&amp;gt;1+taille&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ceci explique la différence entre :: (constructeur) et @ (fonction récursive)&lt;br /&gt;
&lt;br /&gt;
Exemple de type récursif, les arbres binaires :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type bin = Vide | Noeud of int*bin*bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
arbre naire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type arbre n_aire = &lt;br /&gt;
Vide|Node of int ∗ (arbre_naire list)(bancal)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Les structures ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== La récursivité terminale ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les exceptions ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Aspects impératifs dans Caml ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les modules ==&lt;/div&gt;</summary>
		<author><name>Lachand</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO421_:_Programmation_fonctionnelle&amp;diff=5925</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=5925"/>
		<updated>2013-02-12T18:36:12Z</updated>

		<summary type="html">&lt;p&gt;Lachand : /* Les types algébriques */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-421 : 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;
== Détails techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Compléments de cours, TD et TP ===&lt;br /&gt;
&lt;br /&gt;
==== Installer 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;
* Sous MacOS : il semblerait qu&#039;il y ait des paquets MacPorts pour &amp;lt;tt&amp;gt;ocaml&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;emacs&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;tuareg-mode.el&amp;lt;/tt&amp;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;
Pour les exemples simples, vous pouvez aussi utiliser [http://try.ocamlpro.com/ OCaml en ligne]&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;
* 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;
* Le livre de Jason Hickey [http://files.metaprl.org/doc/ocaml-book.pdf Introduction to Objective Caml] (en anglais).&lt;br /&gt;
&lt;br /&gt;
==== Cours ====&lt;br /&gt;
&lt;br /&gt;
==== TD et TP ====&lt;br /&gt;
&lt;br /&gt;
* [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/1213/info421/td1.pdf TD1 : premières expressions en Caml (pdf)]&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;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Attention :&#039;&#039; il ne s&#039;agit pas d&#039;un cours de programmation fonctionelle&lt;br /&gt;
	&amp;lt;/blockquote&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;
=== 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;
* année &#039;80 : Caml (1987), puis CamlLight(1990), puis OCaml(1996), développé&lt;br /&gt;
à l&#039;INRIA. (Dernière version en octobre 2012.)&lt;br /&gt;
* années &#039;90 : Python (version 1.0 en 1994).&lt;br /&gt;
* années &#039;90 : PHP (version 1.0 en 1995).&lt;br /&gt;
* années &#039;90 : Java (version 1.0 en 1996).&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;
&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;&#039;impératifs&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un des slogans de la programmation fonctionnelle en général est&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;&amp;lt;u&amp;gt;Les fonctions sont des valeurs comme les autres&amp;lt;/u&amp;gt;&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
et c&#039;est de là que vient la terminologie... En particulier, il n&#039;y a pas de différence entre les &#039;&#039;instructions&#039;&#039; (qui ont un effet) et les &#039;&#039;expressions&#039;&#039; (qui ont une valeur). Par exemple, en Python,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
x = x+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ou&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if delta &amp;lt; 0:&lt;br /&gt;
    print(&amp;quot;Il n&#039;y a pas de solution&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sont des &#039;&#039;instructions&#039;&#039; : on ne peut pas les mettre dans une variable.&lt;br /&gt;
&lt;br /&gt;
Comme nous le verront, cela a des 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), statiquement typé (nous verrons ce que cela veut dire) qui supporte plusieurs styles de programmation :&lt;br /&gt;
&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 principalement le style fonctionnel, et un peu le style impératif en fin de semestre.&lt;br /&gt;
&lt;br /&gt;
Voici quelques aspects importants du langages que nous essayeront d&#039;aborder pendant le cours :&lt;br /&gt;
&lt;br /&gt;
* fonctions comme valeurs,&lt;br /&gt;
* types de données &#039;&#039;algébriques&#039;&#039;&lt;br /&gt;
* polymorphisme,&lt;br /&gt;
* système d&#039;exceptions,&lt;br /&gt;
* support pour des références et des données mutables (programmation « impure »),&lt;br /&gt;
* système de modules et de foncteurs,&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;récursivité&#039;&#039; sera fondamentale pendant toute la durée du cours...&lt;br /&gt;
&lt;br /&gt;
Un aspect intéressant du langage est que c&#039;est :&lt;br /&gt;
&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;
=== Autres langages fonctionnels ===&lt;br /&gt;
&lt;br /&gt;
Il existe de nombreux autres langages fonctionnels. Par exemple :&lt;br /&gt;
&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;
** Common LISP : [http://en.wikipedia.org/wiki/Common_LISP Wikipedia],&lt;br /&gt;
** Scheme : [http://en.wikipedia.org/wiki/Scheme_%28programming_language%29 Wikipedia].&lt;br /&gt;
* Haskell : [http://en.wikipedia.org/wiki/Haskell_%28programming_language%29 Wikipedia] (inspiré en grande partie de [http://en.wikipedia.org/wiki/Miranda_%28programming_language%29 Miranda]).&lt;br /&gt;
&lt;br /&gt;
Plusieurs langages impératifs intègrent maintenant des aspects propres des langages fonctionnels : Python, Scala, ...&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;
&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;
* analyse de programmes critiques : [http://www.astree.ens.fr/ Astrée],&lt;br /&gt;
* informatique financiere : [http://www.janestreet.com Janestreet Capital] et [http://www.lexifi.com Lexifi].&lt;br /&gt;
&lt;br /&gt;
La viabilité du paradigme fonctionnel se retrouve également dans le langage Erlang ([http://fr.wikipedia.org/wiki/Erlang_%28langage%29 Wikipedia]), un langage fonctionnel développé par Ericsson pour la programmation concurrente de systèmes temps réels.&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, les types algébriques 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;
# 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;
Un des slogans de la programmation fonctionnelle est &#039;&#039;tout est une valeur, ou plus précisément,&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Toute expression &amp;lt;u&amp;gt;a&amp;lt;/u&amp;gt; une valeur.&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette idée n&#039;est pas présente en Python 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: a=12 else: a=13&amp;lt;/tt&amp;gt;&amp;quot; par exemple). En Python, les instructions sont en général séparées par des retours à la ligne 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;
&lt;br /&gt;
* les fonctions du langage (addition, multiplication, opérateurs logiques),&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;
* les relations mathématiques (égalité, plus grand), ... qui sont juste des fonctions renvoyant des booléens,&lt;br /&gt;
* les constantes du langage,&lt;br /&gt;
* les variables de l&#039;environnement,&lt;br /&gt;
* &#039;&#039;les valeurs (en particulier les fonctions) définies par le programmeur&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Bien entendu, comme Caml est typé, il faut respecter 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;
&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;) et les opérations &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt; (et) et &amp;lt;tt&amp;gt;||&amp;lt;/tt&amp;gt; (ou).&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&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;&amp;lt;/math&amp;gt; et &amp;lt;math&amp;gt;2&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;-1&amp;lt;/math&amp;gt;. (Les entiers Caml sont stockés sur 31 bits...) Les opérations associés sont &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; (pour la division entière) et &amp;lt;tt&amp;gt;mod&amp;lt;/tt&amp;gt; (pour le modulo).&lt;br /&gt;
* Les flottants : type &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; pour les réels en virgule flottante. Les opérations usuelles sont &amp;lt;tt&amp;gt;+.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*.&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;/.&amp;lt;/tt&amp;gt;.&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;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* exemples ... *)&lt;br /&gt;
&amp;lt;/source&amp;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écessaire. 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;
=== définitions et 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;, ...&lt;br /&gt;
&lt;br /&gt;
Certaines des variables de l&#039;environnement correspondent à des paramètres de fonction en cours de définition. Ces variables n&#039;ont pas de valeur, mais seulement un type.&lt;br /&gt;
&lt;br /&gt;
==== Environnement ====&lt;br /&gt;
&lt;br /&gt;
* Liste de paires &amp;lt;tt&amp;gt;nom&amp;lt;/tt&amp;gt; / &amp;lt;tt&amp;gt;valeur&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* une nouvelle definition remplace la précédente mais ne l&#039;efface pas, (on ne met pas une valeur à jours)&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;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;let nom = expr&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 nom1 = expr1 and nom2 = expr2&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 nom1 = expr1 and nom2 = expr2&amp;lt;/tt&amp;gt; permet de rajouter des définitions mutuellement récursives.&lt;br /&gt;
&lt;br /&gt;
On peut toujours 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;
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;
&lt;br /&gt;
* : float = 3.1415&lt;br /&gt;
&amp;lt;/source&amp;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 nom = expr1 in expr2&amp;lt;/tt&amp;gt;. Ceci ajoute la définition &amp;lt;tt&amp;gt;nom = expr1&amp;lt;/tt&amp;gt; dans l&#039;environnement, mais seulement pour l&#039;évaluation de l&#039;expression &amp;lt;tt&amp;gt;expr2&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;
&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 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 dont 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;interprète Caml :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # String.length ;;&lt;br /&gt;
&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 fonction est définie comme une variable avec un &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt; et en utilisant le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f = fun n -&amp;gt; n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine = fun n -&amp;gt; int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Une fonction avec plusieurs argument est définie de la même manière avec&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let moyenne3 = fun x y z -&amp;gt; (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le type d&#039;une fonction à plusieurs argument est noté en mettant plusieurs types à gauche de la flèche &amp;lt;tt&amp;gt;-&amp;gt;&amp;lt;/tt&amp;gt;, comme ci dessus : &amp;lt;tt&amp;gt;type_arg1 -&amp;gt; type_arg2 -&amp;gt; type_arg3 -&amp;gt; type_resultat&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarques :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* notez l&#039;absence de mot clé &amp;lt;tt&amp;gt;return&amp;lt;/tt&amp;gt; et l&#039;absence de virgules pour séparer les différents arguments !&lt;br /&gt;
* Le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; permet de définir des fonctions sans leur donner de nom, ce qui n&#039;est pas possible dans les langages comme C ou Java...&lt;br /&gt;
&lt;br /&gt;
On peut également utiliser un raccourci pour définir une fonction sans utiliser le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; : il suffit de mettre les arguments de la fonction avant le signe égal :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f n = n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine n = int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let moyenne3 x y z = (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour appliquer une fonction à des arguments, on écrit simplement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Il n&#039;y a ni parenthèse, ni virgule. Les parenthèses peuvent cependant être nécessaires pour différencier&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 (-0.333 *. 6.)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
et&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(moyenne3 13.5 17.0 -0.333) *. 6.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ou pour que Caml lise correctement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 (17.0 -. 12.0) -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Fonctions récursives ====&lt;br /&gt;
&lt;br /&gt;
Si on essaie de définir une fonction récursivement :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let f n = if (n&amp;lt;1) then 0 else n + f (n-1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Caml répond&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
Error: Unbound value f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
car &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; n&#039;est pas présente dans l&#039;environnement.&lt;br /&gt;
&lt;br /&gt;
Pour rajouter &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; comme variable active (sans valeur) et pouvoir faire une définition récursive, il faut utiliser le mot clé &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let rec f n = if (n&amp;lt;1) then 0 else n + f (n-1);;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les définitions locales peuvent elles aussi être récursives (&amp;lt;tt&amp;gt;let rec ... in ...&amp;lt;/tt&amp;gt;) ou 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;
==== fonctions d&#039;ordre supérieur ====&lt;br /&gt;
&lt;br /&gt;
TODO&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;
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;
Contrairement au cas des tuples, 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; 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;
On peut ajouter un élement devant une liste avec l&#039;opérateur &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; et 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;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# 5::[1;2;3;4] ;;&lt;br /&gt;
- : int list = [5; 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; ne dépend pas de la taille des listes mises en jeux. Par contre, la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot; dépend proportionnellement de la taille de son premier argument. Il faut donc toujour privilégier &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; par rapport à &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot;. En particulier, il est en général mauvais de rajouter des élément en fin de liste en utilisant &amp;quot;&amp;lt;tt&amp;gt;l @ [e]&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Filtrage, première partie : tuples et listes ===&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;filtrage&#039;&#039;, aussi appelé &amp;quot;pattern-matching&amp;quot; est un outils clé pour la programmation en Caml. L&#039;idée est de décomposer une valeur en &amp;quot;sous-valeurs&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les tuples ====&lt;br /&gt;
&lt;br /&gt;
Comme une paire est de la forme &amp;lt;tt&amp;gt;(x,y)&amp;lt;/tt&amp;gt;, on peut décomposer une valeur de type &amp;lt;tt&amp;gt;a*b&amp;lt;/tt&amp;gt; en deux sous valeurs. Voici un exemple de syntaxe : le code de la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt; :&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;
&lt;br /&gt;
Pour évaluer &amp;quot;&amp;lt;tt&amp;gt;premier e&amp;lt;/tt&amp;gt;&amp;quot;, Caml regarde le premier argument &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; et essaie de faire coïncider &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 maintenant récupérer la deuxième composante d&#039;un triplet de la manière suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let second3 t = match t with&lt;br /&gt;
    (_, y, _) -&amp;gt; y&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Notez l&#039;utilisation de &amp;quot;&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;&amp;quot; pour donner la position d&#039;une sous-valeur qui ne sert à rien.&lt;br /&gt;
&lt;br /&gt;
Toutes les variables présentes dans le &#039;&#039;motif&#039;&#039; (la partie à gauche de la flèche) se retrouvent dans l&#039;environnement avec pour valeur, la sous-valeur appropriée. &amp;lt;u&amp;gt;Attention,&amp;lt;/u&amp;gt; ces variables ne se retrouvent dans l&#039;environnement que dans la partie droite de la flèche.&lt;br /&gt;
Ces variables remplacent (temporairement) les variables de même nom qui pouvaient se trouver dans l&#039;environnement. Par exemple, la fonction :&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;
est exactement la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les listes ====&lt;br /&gt;
&lt;br /&gt;
On peut décomposer une liste en deux sous-valeurs :&lt;br /&gt;
&lt;br /&gt;
* le premier élément de la liste,&lt;br /&gt;
* la suite de la liste.&lt;br /&gt;
&lt;br /&gt;
Autrement dit, si la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; n&#039;est pas vide, on peut la décomposer en &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt;. Comme il est possible que la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; soit vide, il y a en fait deux manière de décomposer &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (sans aucune sous-valeur),&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt; (avec deux sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
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;
Les différents cas sont séparés par le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
On peut également décomposer une liste en 3 sous-valeurs : le premier élément, le second élément et la suite de la liste. Dans ce cas, il a trois cas pour une liste arbitraire :&lt;br /&gt;
&lt;br /&gt;
* elle est vide &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (aucune sous-valeur),&lt;br /&gt;
* elle ne contient qu&#039;une seul élément &amp;lt;tt&amp;gt;[e]&amp;lt;/tt&amp;gt; (une sous-valeur),&lt;br /&gt;
* elle contient un premier élément, un deuxième élément, et une suite &amp;lt;tt&amp;gt;a::b::q&amp;lt;/tt&amp;gt; (trois sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
On peut par exemple écrire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus l = match l with&lt;br /&gt;
    [] -&amp;gt; false&lt;br /&gt;
  | [a] -&amp;gt; false&lt;br /&gt;
  | a::b::q -&amp;gt; true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme on peut toujours décomposer une valeur en une sous-valeur (la valeur elle même), on peut toujours avoir un motif de la forme &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;. Toutes les valeurs pourront être décomposées de cette manière, et il faut donc que ce motif soit le dernier. (Sinon, les motifs suivants ne servent à rien...) On parle de motif &#039;&#039;universel&#039;&#039;. (On peut utiliser &amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt; comme motif universel.) Par exemple, on peut réecrire l&#039;exemple précédent :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus&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;
==== Compléments ====&lt;br /&gt;
&lt;br /&gt;
# On peut ajouter des constantes dans les motifs. Le motif ne sera utilisé que lorsque la sous-valeur correspondantes a la valeurs correspondante. Par exemple, si on modélise les entiers de Gauss (« entiers complexes ») par des paires d&#039;entiers, on peut définir :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let imaginaire_pur c = match c with&lt;br /&gt;
    (0,0) -&amp;gt; false&lt;br /&gt;
  | (0,_) -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# On peut grouper des motifs différents pour faire la même chose. Il faut que les variables qui apparaissent dans les motifs soient les mêmes, et qu&#039;elles aient le même type :&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 | 2::_::_::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;
# on peut « garder » les motifs&amp;quot; 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;
&amp;lt;u&amp;gt;Attention&amp;lt;/u&amp;gt; dans le cas où vous utilisez &amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt; : il est conseillé de terminer votre filtrage avec un motif universel pour être sûr que vous n&#039;avez pas oublié de cas.&lt;br /&gt;
# 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;
&lt;br /&gt;
=== Transparence référentielle ===&lt;br /&gt;
&lt;br /&gt;
==== Les types algébriques ====&lt;br /&gt;
&lt;br /&gt;
On peut défnir un synomnyme de type avec le mot clef &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
Exemple : &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type point = float*float&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Types énumérés ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On donne tous les éléments du type&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type jours = Lundi | Mardi | Mercredi | ...&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Type avec 7 éléments. Les éléments commencent forcément par une majuscule.&lt;br /&gt;
&lt;br /&gt;
On peut comparer des éléments avec &amp;quot;=&amp;quot;, &amp;quot;&amp;lt;&amp;quot; et &amp;quot;&amp;gt;&amp;quot; (&amp;lt; et &amp;gt; sont à éviter, il vaut mieux&lt;br /&gt;
écrire une fonction pour comparer) On peut aussi faire du filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let week_end j = match j with&lt;br /&gt;
Samedi -&amp;gt; true&lt;br /&gt;
   | Dimanche -&amp;gt; true&lt;br /&gt;
   | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Construction de types paramètres ===&lt;br /&gt;
 &lt;br /&gt;
Exemple : type des transformations de l&#039;espace avec :&lt;br /&gt;
- Translation&lt;br /&gt;
- Rotation&lt;br /&gt;
- Symetrie&lt;br /&gt;
On aura alors des constructeurs avec des paramètres :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type transformation =&lt;br /&gt;
Rotation of int*point&lt;br /&gt;
| Translation of point&lt;br /&gt;
| SymCentrale of point&lt;br /&gt;
| Homothetie of float*point&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On n&#039;a pas donné explicitement tous les éléments, mais on les a donné implicitement.&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rien = Translation (0.0,0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Autre exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let fait quelquechose t=&lt;br /&gt;
match t with&lt;br /&gt;
Rotation(a, (x, y)− &amp;gt; a mod360! = 0&lt;br /&gt;
|T ranslation(x, y)− &amp;gt; x! = 0.0 &amp;amp;&amp;amp; y! = 0.0&lt;br /&gt;
|SymCentrale(x, y)− &amp;gt; true&lt;br /&gt;
|Homotetie(x, (−, −))− &amp;gt; r! = 1, 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Les types récursifs ===&lt;br /&gt;
&lt;br /&gt;
En Caml&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type node = Node of int*node&lt;br /&gt;
| Vide&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
exemple d&#039;éléments de &amp;quot;node&amp;quot; :&lt;br /&gt;
- Vide&lt;br /&gt;
- Node(0,Vide)&lt;br /&gt;
- Node(1,Node(2,Node(3, Vide)))&lt;br /&gt;
&lt;br /&gt;
Le type &amp;quot;node&amp;quot; est un type récursif. Comme les fonctions récursivent doivent avoir des cas&lt;br /&gt;
de base, les types récursifs doivent avoir des constructeurs &amp;quot;de base&amp;quot; (non récursifs). On peut&lt;br /&gt;
comparer des éléments avec &amp;quot;=&amp;quot;. On peut aussi utiliser le filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
Vide -&amp;gt; 0&lt;br /&gt;
|Node(_,l)-&amp;gt;1+taille l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction taille sur les listes Caml suit le même schéma avec les abréviations Caml.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
| a ::l-&amp;gt;1+taille&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ceci explique la différence entre :: (constructeur) et @ (fonction récursive)&lt;br /&gt;
&lt;br /&gt;
Exemple de type récursif, les arbres binaires :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type bin = Vide | Noeud of int*bin*bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
arbre naire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type arbre n_aire = &lt;br /&gt;
Vide|Node of int ∗ (arbre_naire list)(bancal)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Les structures ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== La récursivité terminale ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les exceptions ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Aspects impératifs dans Caml ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les modules ==&lt;/div&gt;</summary>
		<author><name>Lachand</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO421_:_Programmation_fonctionnelle&amp;diff=5924</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=5924"/>
		<updated>2013-02-12T18:35:20Z</updated>

		<summary type="html">&lt;p&gt;Lachand : /* Les types algébriques */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-421 : 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;
== Détails techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Compléments de cours, TD et TP ===&lt;br /&gt;
&lt;br /&gt;
==== Installer 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;
* Sous MacOS : il semblerait qu&#039;il y ait des paquets MacPorts pour &amp;lt;tt&amp;gt;ocaml&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;emacs&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;tuareg-mode.el&amp;lt;/tt&amp;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;
Pour les exemples simples, vous pouvez aussi utiliser [http://try.ocamlpro.com/ OCaml en ligne]&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;
* 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;
* Le livre de Jason Hickey [http://files.metaprl.org/doc/ocaml-book.pdf Introduction to Objective Caml] (en anglais).&lt;br /&gt;
&lt;br /&gt;
==== Cours ====&lt;br /&gt;
&lt;br /&gt;
==== TD et TP ====&lt;br /&gt;
&lt;br /&gt;
* [http://www.lama.univ-savoie.fr/~hyvernat/Enseignement/1213/info421/td1.pdf TD1 : premières expressions en Caml (pdf)]&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;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Attention :&#039;&#039; il ne s&#039;agit pas d&#039;un cours de programmation fonctionelle&lt;br /&gt;
	&amp;lt;/blockquote&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;
=== 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;
* année &#039;80 : Caml (1987), puis CamlLight(1990), puis OCaml(1996), développé&lt;br /&gt;
à l&#039;INRIA. (Dernière version en octobre 2012.)&lt;br /&gt;
* années &#039;90 : Python (version 1.0 en 1994).&lt;br /&gt;
* années &#039;90 : PHP (version 1.0 en 1995).&lt;br /&gt;
* années &#039;90 : Java (version 1.0 en 1996).&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;
&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;&#039;impératifs&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un des slogans de la programmation fonctionnelle en général est&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;&amp;lt;u&amp;gt;Les fonctions sont des valeurs comme les autres&amp;lt;/u&amp;gt;&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
et c&#039;est de là que vient la terminologie... En particulier, il n&#039;y a pas de différence entre les &#039;&#039;instructions&#039;&#039; (qui ont un effet) et les &#039;&#039;expressions&#039;&#039; (qui ont une valeur). Par exemple, en Python,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
x = x+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ou&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if delta &amp;lt; 0:&lt;br /&gt;
    print(&amp;quot;Il n&#039;y a pas de solution&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sont des &#039;&#039;instructions&#039;&#039; : on ne peut pas les mettre dans une variable.&lt;br /&gt;
&lt;br /&gt;
Comme nous le verront, cela a des 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), statiquement typé (nous verrons ce que cela veut dire) qui supporte plusieurs styles de programmation :&lt;br /&gt;
&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 principalement le style fonctionnel, et un peu le style impératif en fin de semestre.&lt;br /&gt;
&lt;br /&gt;
Voici quelques aspects importants du langages que nous essayeront d&#039;aborder pendant le cours :&lt;br /&gt;
&lt;br /&gt;
* fonctions comme valeurs,&lt;br /&gt;
* types de données &#039;&#039;algébriques&#039;&#039;&lt;br /&gt;
* polymorphisme,&lt;br /&gt;
* système d&#039;exceptions,&lt;br /&gt;
* support pour des références et des données mutables (programmation « impure »),&lt;br /&gt;
* système de modules et de foncteurs,&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;récursivité&#039;&#039; sera fondamentale pendant toute la durée du cours...&lt;br /&gt;
&lt;br /&gt;
Un aspect intéressant du langage est que c&#039;est :&lt;br /&gt;
&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;
=== Autres langages fonctionnels ===&lt;br /&gt;
&lt;br /&gt;
Il existe de nombreux autres langages fonctionnels. Par exemple :&lt;br /&gt;
&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;
** Common LISP : [http://en.wikipedia.org/wiki/Common_LISP Wikipedia],&lt;br /&gt;
** Scheme : [http://en.wikipedia.org/wiki/Scheme_%28programming_language%29 Wikipedia].&lt;br /&gt;
* Haskell : [http://en.wikipedia.org/wiki/Haskell_%28programming_language%29 Wikipedia] (inspiré en grande partie de [http://en.wikipedia.org/wiki/Miranda_%28programming_language%29 Miranda]).&lt;br /&gt;
&lt;br /&gt;
Plusieurs langages impératifs intègrent maintenant des aspects propres des langages fonctionnels : Python, Scala, ...&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;
&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;
* analyse de programmes critiques : [http://www.astree.ens.fr/ Astrée],&lt;br /&gt;
* informatique financiere : [http://www.janestreet.com Janestreet Capital] et [http://www.lexifi.com Lexifi].&lt;br /&gt;
&lt;br /&gt;
La viabilité du paradigme fonctionnel se retrouve également dans le langage Erlang ([http://fr.wikipedia.org/wiki/Erlang_%28langage%29 Wikipedia]), un langage fonctionnel développé par Ericsson pour la programmation concurrente de systèmes temps réels.&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, les types algébriques 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;
# 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;
Un des slogans de la programmation fonctionnelle est &#039;&#039;tout est une valeur, ou plus précisément,&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;Toute expression &amp;lt;u&amp;gt;a&amp;lt;/u&amp;gt; une valeur.&#039;&#039;&lt;br /&gt;
	&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette idée n&#039;est pas présente en Python 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: a=12 else: a=13&amp;lt;/tt&amp;gt;&amp;quot; par exemple). En Python, les instructions sont en général séparées par des retours à la ligne 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;
&lt;br /&gt;
* les fonctions du langage (addition, multiplication, opérateurs logiques),&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;
* les relations mathématiques (égalité, plus grand), ... qui sont juste des fonctions renvoyant des booléens,&lt;br /&gt;
* les constantes du langage,&lt;br /&gt;
* les variables de l&#039;environnement,&lt;br /&gt;
* &#039;&#039;les valeurs (en particulier les fonctions) définies par le programmeur&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Bien entendu, comme Caml est typé, il faut respecter 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;
&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;) et les opérations &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt; (et) et &amp;lt;tt&amp;gt;||&amp;lt;/tt&amp;gt; (ou).&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&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;&amp;lt;/math&amp;gt; et &amp;lt;math&amp;gt;2&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;-1&amp;lt;/math&amp;gt;. (Les entiers Caml sont stockés sur 31 bits...) Les opérations associés sont &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; (pour la division entière) et &amp;lt;tt&amp;gt;mod&amp;lt;/tt&amp;gt; (pour le modulo).&lt;br /&gt;
* Les flottants : type &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; pour les réels en virgule flottante. Les opérations usuelles sont &amp;lt;tt&amp;gt;+.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;-.&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*.&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;/.&amp;lt;/tt&amp;gt;.&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;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(* exemples ... *)&lt;br /&gt;
&amp;lt;/source&amp;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écessaire. 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;
=== définitions et 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;, ...&lt;br /&gt;
&lt;br /&gt;
Certaines des variables de l&#039;environnement correspondent à des paramètres de fonction en cours de définition. Ces variables n&#039;ont pas de valeur, mais seulement un type.&lt;br /&gt;
&lt;br /&gt;
==== Environnement ====&lt;br /&gt;
&lt;br /&gt;
* Liste de paires &amp;lt;tt&amp;gt;nom&amp;lt;/tt&amp;gt; / &amp;lt;tt&amp;gt;valeur&amp;lt;/tt&amp;gt;,&lt;br /&gt;
* une nouvelle definition remplace la précédente mais ne l&#039;efface pas, (on ne met pas une valeur à jours)&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;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;let nom = expr&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 nom1 = expr1 and nom2 = expr2&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 nom1 = expr1 and nom2 = expr2&amp;lt;/tt&amp;gt; permet de rajouter des définitions mutuellement récursives.&lt;br /&gt;
&lt;br /&gt;
On peut toujours 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;
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;
&lt;br /&gt;
* : float = 3.1415&lt;br /&gt;
&amp;lt;/source&amp;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 nom = expr1 in expr2&amp;lt;/tt&amp;gt;. Ceci ajoute la définition &amp;lt;tt&amp;gt;nom = expr1&amp;lt;/tt&amp;gt; dans l&#039;environnement, mais seulement pour l&#039;évaluation de l&#039;expression &amp;lt;tt&amp;gt;expr2&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;
&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 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 dont 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;interprète Caml :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 # String.length ;;&lt;br /&gt;
&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 fonction est définie comme une variable avec un &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt; et en utilisant le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f = fun n -&amp;gt; n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine = fun n -&amp;gt; int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Une fonction avec plusieurs argument est définie de la même manière avec&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let moyenne3 = fun x y z -&amp;gt; (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le type d&#039;une fonction à plusieurs argument est noté en mettant plusieurs types à gauche de la flèche &amp;lt;tt&amp;gt;-&amp;gt;&amp;lt;/tt&amp;gt;, comme ci dessus : &amp;lt;tt&amp;gt;type_arg1 -&amp;gt; type_arg2 -&amp;gt; type_arg3 -&amp;gt; type_resultat&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarques :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* notez l&#039;absence de mot clé &amp;lt;tt&amp;gt;return&amp;lt;/tt&amp;gt; et l&#039;absence de virgules pour séparer les différents arguments !&lt;br /&gt;
* Le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; permet de définir des fonctions sans leur donner de nom, ce qui n&#039;est pas possible dans les langages comme C ou Java...&lt;br /&gt;
&lt;br /&gt;
On peut également utiliser un raccourci pour définir une fonction sans utiliser le mot clé &amp;lt;tt&amp;gt;fun&amp;lt;/tt&amp;gt; : il suffit de mettre les arguments de la fonction avant le signe égal :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let f n = n+1;;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let racine n = int_of_float (sqrt (float_of_int n));;&lt;br /&gt;
val racine : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
# let moyenne3 x y z = (x +. y +. z) /. 3. ;;&lt;br /&gt;
val moyenne3 : float -&amp;gt; float -&amp;gt; float -&amp;gt; float = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour appliquer une fonction à des arguments, on écrit simplement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Il n&#039;y a ni parenthèse, ni virgule. Les parenthèses peuvent cependant être nécessaires pour différencier&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 17.0 (-0.333 *. 6.)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
et&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
(moyenne3 13.5 17.0 -0.333) *. 6.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ou pour que Caml lise correctement&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
moyenne3 13.5 (17.0 -. 12.0) -0.333&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Fonctions récursives ====&lt;br /&gt;
&lt;br /&gt;
Si on essaie de définir une fonction récursivement :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let f n = if (n&amp;lt;1) then 0 else n + f (n-1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Caml répond&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
Error: Unbound value f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
car &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; n&#039;est pas présente dans l&#039;environnement.&lt;br /&gt;
&lt;br /&gt;
Pour rajouter &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; comme variable active (sans valeur) et pouvoir faire une définition récursive, il faut utiliser le mot clé &amp;lt;tt&amp;gt;rec&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# let rec f n = if (n&amp;lt;1) then 0 else n + f (n-1);;&lt;br /&gt;
val f : int -&amp;gt; int = &amp;lt;fun&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les définitions locales peuvent elles aussi être récursives (&amp;lt;tt&amp;gt;let rec ... in ...&amp;lt;/tt&amp;gt;) ou 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;
==== fonctions d&#039;ordre supérieur ====&lt;br /&gt;
&lt;br /&gt;
TODO&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;
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;
Contrairement au cas des tuples, 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; 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;
On peut ajouter un élement devant une liste avec l&#039;opérateur &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; et 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;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
# 5::[1;2;3;4] ;;&lt;br /&gt;
- : int list = [5; 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;
&amp;lt;u&amp;gt;Attention :&amp;lt;/u&amp;gt; la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; ne dépend pas de la taille des listes mises en jeux. Par contre, la complexité de l&#039;opération &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot; dépend proportionnellement de la taille de son premier argument. Il faut donc toujour privilégier &amp;quot;&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt;&amp;quot; par rapport à &amp;quot;&amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt;&amp;quot;. En particulier, il est en général mauvais de rajouter des élément en fin de liste en utilisant &amp;quot;&amp;lt;tt&amp;gt;l @ [e]&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Filtrage, première partie : tuples et listes ===&lt;br /&gt;
&lt;br /&gt;
La notion de &#039;&#039;filtrage&#039;&#039;, aussi appelé &amp;quot;pattern-matching&amp;quot; est un outils clé pour la programmation en Caml. L&#039;idée est de décomposer une valeur en &amp;quot;sous-valeurs&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les tuples ====&lt;br /&gt;
&lt;br /&gt;
Comme une paire est de la forme &amp;lt;tt&amp;gt;(x,y)&amp;lt;/tt&amp;gt;, on peut décomposer une valeur de type &amp;lt;tt&amp;gt;a*b&amp;lt;/tt&amp;gt; en deux sous valeurs. Voici un exemple de syntaxe : le code de la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt; :&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;
&lt;br /&gt;
Pour évaluer &amp;quot;&amp;lt;tt&amp;gt;premier e&amp;lt;/tt&amp;gt;&amp;quot;, Caml regarde le premier argument &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; et essaie de faire coïncider &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 maintenant récupérer la deuxième composante d&#039;un triplet de la manière suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let second3 t = match t with&lt;br /&gt;
    (_, y, _) -&amp;gt; y&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Notez l&#039;utilisation de &amp;quot;&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;&amp;quot; pour donner la position d&#039;une sous-valeur qui ne sert à rien.&lt;br /&gt;
&lt;br /&gt;
Toutes les variables présentes dans le &#039;&#039;motif&#039;&#039; (la partie à gauche de la flèche) se retrouvent dans l&#039;environnement avec pour valeur, la sous-valeur appropriée. &amp;lt;u&amp;gt;Attention,&amp;lt;/u&amp;gt; ces variables ne se retrouvent dans l&#039;environnement que dans la partie droite de la flèche.&lt;br /&gt;
Ces variables remplacent (temporairement) les variables de même nom qui pouvaient se trouver dans l&#039;environnement. Par exemple, la fonction :&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;
est exactement la fonction &amp;lt;tt&amp;gt;fst&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Filtrage sur les listes ====&lt;br /&gt;
&lt;br /&gt;
On peut décomposer une liste en deux sous-valeurs :&lt;br /&gt;
&lt;br /&gt;
* le premier élément de la liste,&lt;br /&gt;
* la suite de la liste.&lt;br /&gt;
&lt;br /&gt;
Autrement dit, si la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; n&#039;est pas vide, on peut la décomposer en &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt;. Comme il est possible que la liste &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; soit vide, il y a en fait deux manière de décomposer &amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (sans aucune sous-valeur),&lt;br /&gt;
* soit &amp;lt;tt&amp;gt;e::q&amp;lt;/tt&amp;gt; (avec deux sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
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;
Les différents cas sont séparés par le symbole &amp;quot;&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
On peut également décomposer une liste en 3 sous-valeurs : le premier élément, le second élément et la suite de la liste. Dans ce cas, il a trois cas pour une liste arbitraire :&lt;br /&gt;
&lt;br /&gt;
* elle est vide &amp;lt;tt&amp;gt;[]&amp;lt;/tt&amp;gt; (aucune sous-valeur),&lt;br /&gt;
* elle ne contient qu&#039;une seul élément &amp;lt;tt&amp;gt;[e]&amp;lt;/tt&amp;gt; (une sous-valeur),&lt;br /&gt;
* elle contient un premier élément, un deuxième élément, et une suite &amp;lt;tt&amp;gt;a::b::q&amp;lt;/tt&amp;gt; (trois sous-valeurs).&lt;br /&gt;
&lt;br /&gt;
On peut par exemple écrire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus l = match l with&lt;br /&gt;
    [] -&amp;gt; false&lt;br /&gt;
  | [a] -&amp;gt; false&lt;br /&gt;
  | a::b::q -&amp;gt; true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Comme on peut toujours décomposer une valeur en une sous-valeur (la valeur elle même), on peut toujours avoir un motif de la forme &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;. Toutes les valeurs pourront être décomposées de cette manière, et il faut donc que ce motif soit le dernier. (Sinon, les motifs suivants ne servent à rien...) On parle de motif &#039;&#039;universel&#039;&#039;. (On peut utiliser &amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt; comme motif universel.) Par exemple, on peut réecrire l&#039;exemple précédent :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let deux_elements_ou_plus&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;
==== Compléments ====&lt;br /&gt;
&lt;br /&gt;
# On peut ajouter des constantes dans les motifs. Le motif ne sera utilisé que lorsque la sous-valeur correspondantes a la valeurs correspondante. Par exemple, si on modélise les entiers de Gauss (« entiers complexes ») par des paires d&#039;entiers, on peut définir :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
  let imaginaire_pur c = match c with&lt;br /&gt;
    (0,0) -&amp;gt; false&lt;br /&gt;
  | (0,_) -&amp;gt; true&lt;br /&gt;
  | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# On peut grouper des motifs différents pour faire la même chose. Il faut que les variables qui apparaissent dans les motifs soient les mêmes, et qu&#039;elles aient le même type :&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 | 2::_::_::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;
# on peut « garder » les motifs&amp;quot; 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;
&amp;lt;u&amp;gt;Attention&amp;lt;/u&amp;gt; dans le cas où vous utilisez &amp;lt;tt&amp;gt;when&amp;lt;/tt&amp;gt; : il est conseillé de terminer votre filtrage avec un motif universel pour être sûr que vous n&#039;avez pas oublié de cas.&lt;br /&gt;
# 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;
&lt;br /&gt;
=== Transparence référentielle ===&lt;br /&gt;
&lt;br /&gt;
=== Les types algébriques ===&lt;br /&gt;
&lt;br /&gt;
On peut défnir un synomnyme de type avec le mot clef &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
Exemple : &lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type point = float*float&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Types énumérés ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On donne tous les éléments du type&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;type jours = Lundi | Mardi | Mercredi | ...&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Type avec 7 éléments. Les éléments commencent forcément par une majuscule.&lt;br /&gt;
&lt;br /&gt;
On peut comparer des éléments avec &amp;quot;=&amp;quot;, &amp;quot;&amp;lt;&amp;quot; et &amp;quot;&amp;gt;&amp;quot; (&amp;lt; et &amp;gt; sont à éviter, il vaut mieux&lt;br /&gt;
écrire une fonction pour comparer) On peut aussi faire du filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let week_end j = match j with&lt;br /&gt;
Samedi -&amp;gt; true&lt;br /&gt;
   | Dimanche -&amp;gt; true&lt;br /&gt;
   | _ -&amp;gt; false&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Construction de types paramètres ===&lt;br /&gt;
 &lt;br /&gt;
Exemple : type des transformations de l&#039;espace avec :&lt;br /&gt;
- Translation&lt;br /&gt;
- Rotation&lt;br /&gt;
- Symetrie&lt;br /&gt;
On aura alors des constructeurs avec des paramètres :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type transformation =&lt;br /&gt;
Rotation of int*point&lt;br /&gt;
| Translation of point&lt;br /&gt;
| SymCentrale of point&lt;br /&gt;
| Homothetie of float*point&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On n&#039;a pas donné explicitement tous les éléments, mais on les a donné implicitement.&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
 let rien = Translation (0.0,0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Autre exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let fait quelquechose t=&lt;br /&gt;
match t with&lt;br /&gt;
Rotation(a, (x, y)− &amp;gt; a mod360! = 0&lt;br /&gt;
|T ranslation(x, y)− &amp;gt; x! = 0.0 &amp;amp;&amp;amp; y! = 0.0&lt;br /&gt;
|SymCentrale(x, y)− &amp;gt; true&lt;br /&gt;
|Homotetie(x, (−, −))− &amp;gt; r! = 1, 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Les types récursifs ===&lt;br /&gt;
&lt;br /&gt;
En Caml&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type node = Node of int*node&lt;br /&gt;
| Vide&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
exemple d&#039;éléments de &amp;quot;node&amp;quot; :&lt;br /&gt;
- Vide&lt;br /&gt;
- Node(0,Vide)&lt;br /&gt;
- Node(1,Node(2,Node(3, Vide)))&lt;br /&gt;
&lt;br /&gt;
Le type &amp;quot;node&amp;quot; est un type récursif. Comme les fonctions récursivent doivent avoir des cas&lt;br /&gt;
de base, les types récursifs doivent avoir des constructeurs &amp;quot;de base&amp;quot; (non récursifs). On peut&lt;br /&gt;
comparer des éléments avec &amp;quot;=&amp;quot;. On peut aussi utiliser le filtrage.&lt;br /&gt;
&lt;br /&gt;
Exemple :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
Vide -&amp;gt; 0&lt;br /&gt;
|Node(_,l)-&amp;gt;1+taille l&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction taille sur les listes Caml suit le même schéma avec les abréviations Caml.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
let rec taille l = match l with&lt;br /&gt;
[]-&amp;gt;0&lt;br /&gt;
| a ::l-&amp;gt;1+taille&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ceci explique la différence entre :: (constructeur) et @ (fonction récursive)&lt;br /&gt;
&lt;br /&gt;
Exemple de type récursif, les arbres binaires :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type bin = Vide | Noeud of int*bin*bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
arbre naire :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ocaml&amp;quot;&amp;gt;&lt;br /&gt;
type arbre n_aire = &lt;br /&gt;
Vide|Node of int ∗ (arbre_naire list)(bancal)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Les structures ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== La récursivité terminale ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les exceptions ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Aspects impératifs dans Caml ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Les modules ==&lt;/div&gt;</summary>
		<author><name>Lachand</name></author>
	</entry>
</feed>