<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Le blog de SpiceGuid &#187; Objective Caml</title>
	<atom:link href="https://blog.developpez.com/damien-guichard/pcategory/programmation-fonctionnelle/objective-caml/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/damien-guichard</link>
	<description></description>
	<lastBuildDate>Mon, 28 May 2012 16:08:44 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Méditation sur une calculatrice</title>
		<link>https://blog.developpez.com/damien-guichard/p8966/programmation-fonctionnelle/meditation_sur_une_calculatrice</link>
		<comments>https://blog.developpez.com/damien-guichard/p8966/programmation-fonctionnelle/meditation_sur_une_calculatrice#comments</comments>
		<pubDate>Wed, 02 Jun 2010 13:53:42 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Objective Caml]]></category>
		<category><![CDATA[Programmation fonctionnelle]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Un exercice simple pour débutant en ocaml c&#8217;est d&#8217;écrire un interpréteur pour un petit langage simple comme par exemple une calculatrice : type arithmetic = &#124; Cst of int &#124; Neg of arithmetic &#124; Add of binary &#124; Sub of binary &#124; Mul of binary &#124; Div of binary and binary = arithmetic * arithmetic Mais cet exercice anodin change complètement de nature quand on passe à un langage fortement normalisant, dans ce cas vous [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><center><a href="http://caml.inria.fr/" target="_blank"><img src="http://damien-guichard.developpez.com/logos/logo_caml.png"/></a></center></p>
<p>Un exercice simple pour débutant en ocaml c&rsquo;est d&rsquo;écrire un interpréteur pour un petit langage simple comme par exemple une calculatrice :</p>
<pre>
type arithmetic =
   | Cst of int
   | Neg of arithmetic
   | Add of binary
   | Sub of binary
   | Mul of binary
   | Div of binary
and binary =
   arithmetic * arithmetic
</pre>
<p>Mais cet exercice anodin change complètement de nature quand on passe à un langage fortement normalisant, dans ce cas vous devez aussi prouver que le programme se termine toujours et sans accident, quelles que soient les circonstances.    </p>
<p><span id="more-28"></span></p>
<p>Cette preuve ce fait en deux étapes :</p>
<ul>
<li>d&rsquo;abord il changer d&rsquo;algèbre initiale</li>
<li>ensuite il faut établir une égalité entre les deux types algébriques</li>
</ul>
<p>Le changement d&rsquo;algèbre initiale se fait en paraphrasant la déclaration du type, en remplaçant chaque occurrence de <em>arithmetic</em> par une occurrence de <em>fold f</em> :</p>
<pre>
let rec fold f = function
   | Cst n -> f#cst n 
   | Neg a -> f#neg (fold f a)
   | Add (a,b) -> f#add (fold f a) (fold f b)
   | Sub (a,b) -> f#sub (fold f a) (fold f b)
   | Mul (a,b) -> f#mul (fold f a) (fold f b)
   | Div (a,b) -> f#div (fold f a) (fold f b)
</pre>
<p>Le paramètre <em>f</em> est une égalité entre les deux types algébriques :       </p>
<pre>
let id x = x   
   
let eval =
   fold (
      object
         method cst = id
         method neg = (~-)
         method add = ( + )
         method sub = ( - ) 
         method mul = ( * ) 
         method div = ( / )
      end )
</pre>
<p>À cette étape on est à l&rsquo;abri des boucles infinies.<br />
Mais on n&rsquo;est pas à l&rsquo;abri des interruptions intempestives, par exemple lors d&rsquo;une division par zéro.    </p>
<pre>
# eval (Div(Cst 1,Cst 0));;
Exception: Division_by_zero.
</pre>
<p>Dans les langages fortements normalisants les exceptions n&rsquo;existent pas.<br />
Pour simuler les exceptions on utilise la monade <em>result</em> pour propager le diagnostic d&rsquo;erreur.</p>
<pre>
type ('a,'b) result =
   | Ok of 'a
   | Error of 'b 

let ok1 f v =
   match v with
   | Ok x -> Ok (f x)
   | Error _ -> v

let ok2 f v1 v2 =
   match v1,v2 with
   | Ok x1,Ok x2 -> Ok (f x1 x2) 
   | Error _, _ -> v1
   | _, Error _ -> v2

let result2 f v1 v2 =
   match v1,v2 with
   | Ok x1,Ok x2 -> f x1 x2 
   | Error _, _ -> v1
   | _, Error _ -> v2
   
let safe_division a b =  
   if b=0 then Error "Division_by_zero"
   else Ok (a/b)  
</pre>
<p>À l&rsquo;aide de cette monade <em>result</em> on peut définir une nouvelle égalité qui prend en compte les possibilités d&rsquo;erreur :  </p>
<pre>
let ok n = Ok n   
      
let eval =
   fold (
      object
         method cst = ok
         method neg = ok1 (~-)
         method add = ok2 ( + )
         method sub = ok2 ( - ) 
         method mul = ok2 ( * ) 
         method div = result2 safe_division
      end )
</pre>
<p>Cette fois le programme suit son cours jusqu&rsquo;au bout, sans interruption :</p>
<pre>
# eval (Div(Cst 1,Cst 0));;
- : (int, string) result = Error "Division_by_zero"      
</pre>
<p>Bien sûr un tel raffinement de style n&rsquo;est pas forcément utile ou même désirable dans chaque code ocaml. Le langage étant multi-paradigmes par nature il vous invite à trouver le style qui vous convient le mieux.</p>
<p>Cependant, avec cette introduction courte et informelle sur les récurseurs et les monades, j&rsquo;espère avoir donné quelques encouragements à ceux qui voudraient faire le grand saut vers un assistant de preuve.</p>
<p>&#8211; damien</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OCaml Meeting 2010 à Paris le 16 Avril</title>
		<link>https://blog.developpez.com/damien-guichard/p8721/programmation-fonctionnelle/ocaml_meeting_2010_a_paris_le_16_avril</link>
		<comments>https://blog.developpez.com/damien-guichard/p8721/programmation-fonctionnelle/ocaml_meeting_2010_a_paris_le_16_avril#comments</comments>
		<pubDate>Fri, 12 Mar 2010 16:23:33 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Objective Caml]]></category>
		<category><![CDATA[Programmation fonctionnelle]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Sylvain Le Gall et l&#8217;équipe organisatrice de la 3ième rencontre des programmeurs Objective-Caml vous donnent rendez-vous le 16 Avril à Paris. Malheureusement je ne pourrai pas être présent cette année. Hello, For the third time, I am proud to invite all OCaml enthusiasts to join us at OCaml Meeting 2010 in Paris. This year event takes place in Paris on Friday 16th April 2010. Subscription is opened and will be closed on Friday 2nd April [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><center><a href="http://caml.inria.fr/" target="_blank"><img src="http://damien-guichard.developpez.com/logos/logo_caml.png"/></a></center></p>
<p><strong>Sylvain Le Gall</strong> et l&rsquo;équipe organisatrice de la 3ième rencontre des programmeurs Objective-Caml vous donnent rendez-vous le 16 Avril à Paris.</p>
<p>Malheureusement je ne pourrai pas être présent cette année. </p>
<p><span id="more-27"></span></p>
<p>Hello,</p>
<p>For the third time, I am proud to invite all OCaml enthusiasts to join<br />
us at OCaml Meeting 2010 in Paris.</p>
<p>This year event takes place in Paris on Friday 16th April 2010.<br />
Subscription is opened and will be closed on Friday 2nd April 2010.</p>
<p>Presentations include:</p>
<ul>
<li>Enforcing Type-Safe Linking using Inter-Package Relationships for<br />
  OCaml Debian packages</li>
<li>The Ocamlviz visualization toolkit</li>
<li>Cluster computing in Ocaml</li>
<li>Ocaml in a web startup</li>
<li>React, functional reactive programming for OCaml</li>
<li>OASIS, a Cabal like system for OCaml</li>
<li>OPA, same web, but with types and lambda</li>
<li>OC4MC, Objective Caml for MultiCore</li>
<li>Lwt, Cooperative Light-Weight Threads</li>
<li>naclgrid: the collaborative rendering farm, a JoCaml-powered<br />
  desktop grid</li>
</ul>
<p>The meeting is sponsored by INRIA, the Caml Consortium and OCamlCore.<br />
Inscription is free but the number of participants is limited.</p>
<p>Further information and inscriptions:</p>
<p>http://wiki.cocan.org/events/europe/ocamlmeetingparis2010</p>
<p>The day after OCaml Meeting, Mehdi Dogguy from PPS helps me to organize<br />
an informal day where OCaml teams can meet to work. We will have 2<br />
classrooms, each can host 45 persons. There will be an internet access<br />
and a blackboard in each room. Inscription is free.</p>
<p>Further information and inscriptions:</p>
<p>http://wiki.cocan.org/events/europe/ocamlhackingday2010</p>
<p>Hope to see a lot of you,</p>
<p>Regards,</p>
<p><strong>Sylvain Le Gall</strong> on behalf of the OCaml Meeting organization team.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Les files de priorité (les bases)</title>
		<link>https://blog.developpez.com/damien-guichard/p8644/programmation-fonctionnelle/les_files_de_priorite_les_bases</link>
		<comments>https://blog.developpez.com/damien-guichard/p8644/programmation-fonctionnelle/les_files_de_priorite_les_bases#comments</comments>
		<pubDate>Thu, 18 Feb 2010 16:54:03 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Objective Caml]]></category>
		<category><![CDATA[Programmation fonctionnelle]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le tas binaire est un tableau qui implémente un arbre pseudo-complet vérifiant la propriété de tas. Un tableau est de taille fixe. Par conséquent un tas binaire est borné, on ne peut y insérer qu&#8217;un nombre fixe et limité d&#8217;éléments. Bien sûr on pourrait redimensionner le tableau dynamiquement, mais cela a un impact négatif sur le coût des opérations. Qu&#8217;on prêche le style impératif ou le style fonctionnel est étrangé à l&#8217;affaire. La bonne question [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><center><a href="http://caml.inria.fr/" target="_blank"><img src="http://damien-guichard.developpez.com/logos/logo_caml.png"/></a></center></p>
<p>Le tas binaire est un tableau qui implémente un arbre pseudo-complet vérifiant la propriété de tas.<br />
Un tableau est de taille fixe. Par conséquent un tas binaire est borné, on ne peut y insérer qu&rsquo;un nombre fixe et limité d&rsquo;éléments. Bien sûr on pourrait redimensionner le tableau dynamiquement, mais cela a un impact négatif sur le coût des opérations.<br />
Qu&rsquo;on prêche le style impératif ou le style fonctionnel est étrangé à l&rsquo;affaire.<br />
La bonne question c&rsquo;est de savoir si on connait d&rsquo;avance le nombre d&rsquo;éléments à insérer ou non. </p>
<p>Si on le connait alors un tas binaire fera très bien l&rsquo;affaire.<br />
Si on ne le connait pas, alors autant opter tout de suite pour un arbre binaire, même si on veut garder un style impératif.<br />
Ça serait exactement la même problématique avec un dictionnaire. On peut faire une recherche dichotomique dans un tableau trié. Ou alors on peut faire une recherche dans un arbre ordonnée.<br />
Dans les deux cas l&rsquo;algorithme de recherche est le même, il s&rsquo;agit dune boucle qui à chaque étape découpe l&rsquo;espace de recherche en deux moitiés dont une seule peut contenir l&rsquo;élément recherché.<br />
Le paradigme a bien un impact sur le programmeur mais c&rsquo;est parce que le programmeur est trop attaché à la syntaxe.<br />
En réalité le paradigme impacte plus fortement la façon de faire que la façon de penser.<br />
L&rsquo;expérience aussi est un facteur qui impacte la façon de faire.<br />
C&rsquo;est pourquoi je préfère parler de style plutôt que de paradigme.</p>
<p><span id="more-26"></span></p>
<h3 style="text-align: left">Le tas de Braun</h3>
<p>Un petit rappel de quelques définitions :</p>
<ul>
<li><a href="http://algo.developpez.com/faq/?page=types#structure_de_tas" target="_blank">propriété de tas</a></li>
<li><a href="http://algo.developpez.com/faq/?page=arbres#arbre_binaire_complet" target="_blank">arbre complet</a></li>
<li><a href="http://algo.developpez.com/faq/?page=arbres#arbre_braun" target="_blank">arbre de Braun</a></li>
</ul>
<p>On l&rsquo;appelle tas de Braun parce que l&rsquo;insertion répétée dans l&rsquo;arbre vide produit un arbre de Braun.<br />
Un autre nom est <em>heap-ordered binary tree</em> mais c&rsquo;est moins spécifique.</p>
<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">type 'a heap = <br />
&nbsp; | E (* 'a empty heap *) <br />
&nbsp; | N of 'a non_empty_heap <br />
and 'a non_empty_heap = <br />
&nbsp; {mutable l: 'a heap; mutable e: 'a; mutable r: 'a heap}</div></div>

</pre>
<p>Remarques :</p>
<ul>
<li>on a un type tas non-vide, il n&rsquo;y aura pas d&rsquo;exceptions dans le code, la contrainte sur l&rsquo;argument des fonctions <em>find_max</em> et <em>remove_max</em> sera exprimée par le type, la contrainte sur le résultat de <em>insert</em> également</li>
<li>les champs sont mutables, c&rsquo;est parce qu&rsquo;on va utiliser le même type pour les deux styles de programmation, les algorithmes seront les mêmes, mais dans un cas on fera de la copie, dans l&rsquo;autre on fera de la modification sur place</li>
</ul>
<p>La fonction <em>find_max</em> est triviale :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">let find_max {e=m} = m</div></div>
<h3 style="text-align: left">Le style fonctionnel</h3>
<p>On devrait dire le style immutable.<br />
Je commence toujours par le style immutable parce que c&rsquo;est plus lisible.<br />
J&rsquo;ai choisi un tas-max plutôt qu&rsquo;un tas-min, pour un tas-min il n&rsquo;y aura qu&rsquo;à changer le signe où inverser le signe de la fonction <em>compare</em>.</p>
<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">let rec add x = function <br />
&nbsp; | E -&gt; <br />
&nbsp; &nbsp; &nbsp; {l=E;e=x;r=E} <br />
&nbsp; | N n -&gt; &nbsp;<br />
&nbsp; &nbsp; &nbsp; if compare n.e x &gt; 0 then {l=N (add x n.r);e=n.e;r=n.l} &nbsp;<br />
&nbsp; &nbsp; &nbsp; else {l=N (add n.e n.r);e=x;r=n.l} <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
let rec remove_max = function <br />
&nbsp; | {l=E;r=t} | {r=E;l=t} -&gt; <br />
&nbsp; &nbsp; &nbsp; t <br />
&nbsp; | {l=N l;e=e;r=N r} -&gt; <br />
&nbsp; &nbsp; &nbsp; if compare l.e r.e &gt; 0 then N {l=remove_max l;e=l.e;r=N r} <br />
&nbsp; &nbsp; &nbsp; else N {l=N l;e=r.e;r=remove_max r}</div></div>

</pre>
<h3 style="text-align: left">Le style impératif</h3>
<p>On devrait dire le style mutable.<br />
Je traduis à partir de la version en style immutable.</p>
<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">let rec insert x = function <br />
&nbsp; | E -&gt; <br />
&nbsp; &nbsp; &nbsp; {l=E;e=x;r=E} <br />
&nbsp; | N n -&gt; <br />
&nbsp; &nbsp; &nbsp; let nr = n.r in <br />
&nbsp; &nbsp; &nbsp; n.r &lt;- n.l; <br />
&nbsp; &nbsp; &nbsp; if compare n.e x &gt; 0 then n.l &lt;- N (insert x nr) <br />
&nbsp; &nbsp; &nbsp; else (n.l &lt;- N (insert n.e nr); n.e &lt;- x); <br />
&nbsp; &nbsp; &nbsp; n <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
let rec delete_max h = <br />
&nbsp; match h with &nbsp;<br />
&nbsp; | {l=E;r=t} | {r=E;l=t} -&gt; <br />
&nbsp; &nbsp; &nbsp; t <br />
&nbsp; | {l=N l;e=e;r=N r} -&gt; <br />
&nbsp; &nbsp; &nbsp; if compare l.e r.e &gt; 0 then (h.e &lt;- l.e; h.l &lt;- delete_max l) &nbsp;<br />
&nbsp; &nbsp; &nbsp; else (h.e &lt;- r.e; h.r &lt;- delete_max r); <br />
&nbsp; &nbsp; &nbsp; N h</div></div>

</pre>
<h3 style="text-align: left">Autres opérations</h3>
<p>Il faut mentionner qu&rsquo;un tas de Braun offre des tas de possibilités de variantes et d&rsquo;extensions qui seraient bien plus difficiles à implanter à l&rsquo;aide d&rsquo;un tas binaire.<br />
Je ne vais pas être exhaustif sur ce point, je vais cependant en citer deux.<br />
Il est également possible de supprimer un élément arbitraire dans un tas en le faissant percoler jusqu&rsquo;à la racine puis en invoquant <em>remove_max</em>.</p>
<h3 style="text-align: left">La fusion </h3>
<p>Il est possible de fusionner deux tas de Braun en un seul tas.</p>
<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">let rec join ha hb = <br />
&nbsp; match ha,hb with <br />
&nbsp; | t,E | E,t -&gt; <br />
&nbsp; &nbsp; &nbsp; t <br />
&nbsp; | N a,N b -&gt; <br />
&nbsp; &nbsp; &nbsp; if compare a.e b.e &gt; 0 then N {l=join a.l a.r;e=a.e;r=hb} <br />
&nbsp; &nbsp; &nbsp; else N {l=ha;e=b.e;r=join b.l b.r}</div></div>

</pre>
<p>On peut accélérer l&rsquo;opération de fusion à l&rsquo;aide d&rsquo;une technique dite de &laquo;&nbsp;structural bootstrapping&nbsp;&raquo;.<br />
Grâce à cette technique il est possible de fusionner deux tas simplement en insérant l&rsquo;un dans l&rsquo;autre.</p>
<h3 style="text-align: left">L&rsquo;arbre tournoi</h3>
<p>On peut modifier légèrement les opérations d&rsquo;insertion et de suppression pour que le tas restitue l&rsquo;ordre d&rsquo;insertion quand on le parcourre dans l&rsquo;ordre infixe.<br />
Toutefois cette modification a un impact sur la performance, le tas n&rsquo;est plus pseudo-complet comme un arbre de Braun.  </p>
<p>Typiquement on insère les scores dans l&rsquo;arbre tournoi, le gagnant est toujours à la racine.<br />
Le parcourt infixe restitue la liste des scores dans l&rsquo;ordre d&rsquo;apparition des joueurs.</p>
<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">let rec add x = function <br />
&nbsp; | E -&gt; <br />
&nbsp; &nbsp; &nbsp; {l=E;e=x;r=E} <br />
&nbsp; | N n -&gt; &nbsp;<br />
&nbsp; &nbsp; &nbsp; if compare n.e x &gt; 0 then {n with r=N (add x n.r)} &nbsp;<br />
&nbsp; &nbsp; &nbsp; else {l=N n;e=x;r=E} <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
let rec remove_max = function <br />
&nbsp; | {l=E;r=t} | {r=E;l=t} -&gt; <br />
&nbsp; &nbsp; &nbsp; t <br />
&nbsp; | {l=N l;e=e;r=N r} as t -&gt; <br />
&nbsp; &nbsp; &nbsp; if compare l.e r.e &gt; 0 then <br />
&nbsp; &nbsp; &nbsp; &nbsp; N{l=l.l;e=l.e;r=remove_max {t with l=l.r}} <br />
&nbsp; &nbsp; &nbsp; else <br />
&nbsp; &nbsp; &nbsp; &nbsp; N{l=remove_max {t with r=r.l};e=r.e;r=r.r}</div></div>

</pre>
<h3 style="text-align: left">Conclusion</h3>
<p>La chose à retenir c&rsquo;est que ce n&rsquo;est pas le fonctionnel qui force à changer de structure de données.<br />
Ce qui force à changer de structure de données c&rsquo;est le fait qu&rsquo;un tableau n&rsquo;est pas toujours la meilleure option. Utiliser une liste ou un arbre au lieu d&rsquo;un tableau n&rsquo;interdit pas le style mutable.<br />
Il n&rsquo;y a pas un paradigme impératif qui s&rsquo;oppose à un paradigme impératif fonctionnel, il y a juste le style mutable et le style immutable qui sont deux façons d&rsquo;implanter un même algorithme pour une même structure de données.<br />
On peut d&rsquo;ailleurs très bien adopter le style immutable avec un langage à objets si le ramasse-miettes est suffisamment efficace pour ça.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Personnalisez vos fichiers source</title>
		<link>https://blog.developpez.com/damien-guichard/p8578/programmation-fonctionnelle/objective-caml/personnalisez_vos_fichiers_source</link>
		<comments>https://blog.developpez.com/damien-guichard/p8578/programmation-fonctionnelle/objective-caml/personnalisez_vos_fichiers_source#comments</comments>
		<pubDate>Sat, 30 Jan 2010 15:56:10 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Objective Caml]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Un MIME (Multipurpose Internet Mail Extension) est une information système pour identifier les types de fichier et leur affecter certains attributs comme une commande par défaut ou une icône personnalisée. Ce billet vous propose d&#8217;agrémenter votre station de développement Objective-Caml à l&#8217;aide d&#8217;un MIME pour vos fichiers source. Bien sûr ça n&#8217;est qu&#8217;un exemple que vous pourrez adapter à votre application ou à votre langage de programmation favori. D&#8217;abord un avertissement : l&#8217;ajout de MIMEs [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><center><a href="http://caml.inria.fr/" target="_blank"><img src="http://damien-guichard.developpez.com/logos/logo_caml.png"/></a></center></p>
<p>Un MIME (Multipurpose Internet Mail Extension) est une information système pour identifier les types de fichier et leur affecter certains attributs comme une commande par défaut ou une icône personnalisée.  </p>
<p>Ce billet vous propose d&rsquo;agrémenter votre station de développement <a href="http://caml.inria.fr/" target="_blank">Objective-Caml</a> à l&rsquo;aide d&rsquo;un MIME pour vos fichiers source.<br />
Bien sûr ça n&rsquo;est qu&rsquo;un exemple que vous pourrez adapter à votre application ou à votre langage de programmation favori.</p>
<p><span id="more-12"></span></p>
<p>D&rsquo;abord un <strong>avertissement</strong> :</p>
<ul>
<li> l&rsquo;ajout de MIMEs est une opération potentiellement dangereuse, en effet si vous perdez tous vos MIMEs vous ne pourrez plus monter un volume en cliquant sur son icône et vous devrez retourner à la console pour réaliser la plupart des opérations mêmes les plus élémentaires</li>
<li> tapez la commande <ins>update-mime-database /usr/share/mime</ins> dans une console </li>
<li> si cette commande n&rsquo;est pas reconnue alors votre système ne gère pas la mise à jour des MIMEs et vous devrez opérer à la main, à condition de savoir ce que vous faites </li>
</ul>
<p>Sinon créez un fichier <ins>/usr/share/mime/packages/ocaml.xml</ins> et éditez-le avec ce contenu :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt; <br />
&lt;mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'&gt; <br />
&nbsp; &lt;mime-type type=&quot;text/ocaml-source&quot;&gt; <br />
&nbsp; &nbsp; &lt;comment&gt;Objective-Caml source&lt;/comment&gt; <br />
&nbsp; &nbsp; &lt;glob pattern=&quot;*.ml&quot;/&gt; <br />
&nbsp; &lt;/mime-type&gt; <br />
&nbsp; &lt;mime-type type=&quot;text/ocaml-interface&quot;&gt; <br />
&nbsp; &nbsp; &lt;comment&gt;Objective-Caml interface&lt;/comment&gt; <br />
&nbsp; &nbsp; &lt;glob pattern=&quot;*.mli&quot;/&gt; <br />
&nbsp; &lt;/mime-type&gt; <br />
&lt;/mime-info&gt;</div></div>
<p>Puis exécutez la commande <ins>update-mime-database /usr/share/mime</ins>.</p>
<p>Vous pouvez alors définir tous les paramètres liés à un MIME comme une icône personnalisée et une action par défaut pour votre gestionnaire de fichiers.</p>
<p>Par exemple définir une icône personnalisée pour <strong>ROX-filer</strong> :</p>
<ul>
<li> sauvez le fichier image en tête de cet article </li>
<li> sélectionnez le menu <ins>File/Set Icon&#8230;</ins> sur un fichier <strong>*.ml</strong> </li>
<li> cochez la case <ins>Pour tous les fichiers de type &lsquo;text/ocaml-source</ins> </li>
<li> lâchez l&rsquo;image sur la zone réservée à cet effet</li>
</ul>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qualification à l&#8217;intérieur des modules</title>
		<link>https://blog.developpez.com/damien-guichard/p8514/programmation-fonctionnelle/qualification_a_l_interieur_des_modules_1</link>
		<comments>https://blog.developpez.com/damien-guichard/p8514/programmation-fonctionnelle/qualification_a_l_interieur_des_modules_1#comments</comments>
		<pubDate>Tue, 12 Jan 2010 19:28:44 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Objective Caml]]></category>
		<category><![CDATA[Programmation fonctionnelle]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le billet d&#8217;aujourd&#8217;hui a pour but de faire toute la lumière sur la qualification à l&#8217;intérieur des modules Objective-Caml. Un module paramétré est un module-fonction, c&#8217;est-à-dire une fonction d&#8217;un module-type vers un module-type qui accepte un module-valeur pour argument réel. La définition d&#8217;un module paramétré conduit fréquemment à ce genre de code où Graphics est l&#8217;argument formel du module-fonction Draw. module type Graphics = sig type color = Black &#124; White type point = {x:int;y:int} [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><center><a href="http://caml.inria.fr/" target="_blank"><img src="http://caml.inria.fr//pub/logos/caml-inria-fr.128x58.gif"/></a></center></p>
<p>Le billet d&rsquo;aujourd&rsquo;hui a pour but de faire toute la lumière sur la qualification à l&rsquo;intérieur des modules Objective-Caml.</p>
<p><span id="more-25"></span></p>
<p>Un module paramétré est un module-fonction, c&rsquo;est-à-dire une fonction d&rsquo;un module-type vers un module-type qui accepte un module-valeur pour argument réel.</p>
<p>La définition d&rsquo;un module paramétré conduit fréquemment à ce genre de code où Graphics est l&rsquo;argument formel du module-fonction Draw. </p>
<pre>
module type Graphics
  =
  sig
    type color = Black | White
    type point = {x:int;y:int}
    val draw_line : int -> int -> int -> int -> unit
  end

module Draw (G: Graphics)
  =
  struct
    let pen = Black
    let background = White
    let connect a b = G.draw_line a.x a.y b.x b.y 
  end
</pre>
<p>Au premier abord il est surprenant qu&rsquo;OCaml n&rsquo;accepte pas ce code.<br />
Il ne l&rsquo;accepte pas pour deux raisons similaires :  </p>
<ul>
<li>les couleurs Black et White ne sont pas définies dans le module Draw</li>
<li>les champs x et y ne sont pas définis dans le module Draw</li>
</ul>
<p>Le contournement évident consiste à tout qualifier par le module G.</p>
<pre>
module Draw (G: Graphics)
  =
  struct
    let pen = G.Black
    let background = G.White
    let connect a b = G.draw_line a.G.x a.G.y b.G.x b.G.y 
  end
</pre>
<p>Une fois tout qualifié par le module G ocaml accepte le code.<br />
Mais cette solution peut vite devenir assez lourde.<br />
Il y a d&rsquo;autres moyens pour soulager la notation.</p>
<p>Un moyen classique consiste à ouvrir le module G de façon à accéder à ses définitions sans avoir à qualifier systématiquement.</p>
<pre>
module Draw (G: Graphics)
  =
  struct
    open G
    let pen = Black
    let background = White
    let connect a b = draw_line a.x a.y b.x b.y 
  end
</pre>
<p>Toutefois un reproche que l&rsquo;on peut faire à l&rsquo;ouverture de module c&rsquo;est qu&rsquo;on ouvre tout ou rien. Il n&rsquo;est pas possible, à l&rsquo;aide d&rsquo;<strong>open</strong>, d&rsquo;ouvrir le type <em>G.point</em> parce que les champs <em>G.x</em> et <em>G.y</em> impactent beaucoup la lisibilité mais de laisser le type <em>G.color</em> fermé parce que <em>G.Black</em> et <em>G.White</em> ne sont pas très gênants.<br />
Ça n&rsquo;est pas possible à l&rsquo;aide d&rsquo;<strong>open</strong> mais ça l&rsquo;est à l&rsquo;aide d&rsquo;une égalité de types.<br />
L&rsquo;idée c&rsquo;est de déclarer un type <em>point</em> équivalent au type <em>G.point</em>.<br />
Ce type local agira comme un alias pour le type <em>G.point</em>.<br />
De cette façon le module G reste fermé mais on peut accéder directement aux composantes x et y sans les qualifier.</p>
<pre>
module Draw (G: Graphics)
  =
  struct
    type point = G.point = {x:int;y:int}
    let pen = G.Black
    let background = G.White
    let connect a b = G.draw_line a.x a.y b.x b.y 
  end
</pre>
<p>En allant jusqu&rsquo;au bout de cette logique on peut carrément inclure le module G, dans ce cas le module Draw contient une copie complète du module G et il n&rsquo;y a plus rien à qualifier.</p>
<pre>
module Draw (G: Graphics)
  =
  struct
    include G
    let pen = Black
    let background = White
    let connect a b = draw_line a.x a.y b.x b.y 
  end
</pre>
<p>Attention toutefois à ne pas abuser du <strong>include</strong> là où un <strong>open</strong> ferait très bien l&rsquo;affaire.<br />
Le <strong>include</strong> ajoute tout le module à l&rsquo;interface du module en cours.<br />
Il a donc un effet à l&rsquo;extérieur du module alors que l&rsquo;effet de <strong>open</strong> est limité à l&rsquo;intérieur.<br />
N&rsquo;utilisez <strong>include</strong> que si c&rsquo;est nécessaire pour implanter l&rsquo;interface voulue, si vous n&rsquo;avez que besoin d&rsquo;alléger la qualification dans l&rsquo;implantation alors c&rsquo;est <strong>open</strong> qu&rsquo;il vous faut.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hello Developpez ! avec LibGlade/XML</title>
		<link>https://blog.developpez.com/damien-guichard/p7748/programmation-fonctionnelle/hello_developpez_avec_libglade_xml_1</link>
		<comments>https://blog.developpez.com/damien-guichard/p7748/programmation-fonctionnelle/hello_developpez_avec_libglade_xml_1#comments</comments>
		<pubDate>Mon, 15 Jun 2009 14:49:50 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Logiciel Libre]]></category>
		<category><![CDATA[Objective Caml]]></category>
		<category><![CDATA[Programmation fonctionnelle]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Hier, afin d&#8217;illustrer l&#8217;usage de LablGtk2, le binding GTK+ pour le langage Objective-Caml j&#8217;ai posté le code de ce Hello Developpez tout ce qu&#8217;il y a de plus basique : Toutefois, une comparaison ligne à ligne avec la version Gtk2Hs pour Haskell, grâcieusement postée par Alp, n&#8217;était pas possible puisque mon code n&#8217;utilisait pas libglade. On pourrait se demander pour quelle raison utiliser libglade car OCaml est un langage statiquement typé particulièrement sûr comparé à [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://caml.inria.fr/" target="_blank"><img src="http://caml.inria.fr//pub/logos/caml-inria-fr.128x58.gif"/></a></p>
<p>Hier, afin d&rsquo;illustrer l&rsquo;usage de <a href="http://wwwfun.kurims.kyoto-u.ac.jp/soft/olabl/lablgtk.html" target="_blank">LablGtk2, le binding GTK+</a> pour le <a href="http://caml.inria.fr/" target="_blank">langage Objective-Caml</a> j&rsquo;ai posté le code de ce Hello Developpez tout ce qu&rsquo;il y a de plus basique :</p>
<p><img src="http://damien-guichard.developpez.com/illustrations/developpez_0077.jpg"/></p>
<p>Toutefois, une comparaison ligne à ligne avec <a href="http://blog.developpez.com/alp/p7737/programmation-fonctionnelle/hello-gtk2hs/#more7737" target="_blank">la version Gtk2Hs pour Haskell</a>, grâcieusement postée par <strong>Alp</strong>, n&rsquo;était pas possible puisque mon code n&rsquo;utilisait pas <em>libglade</em>. </p>
<p><span id="more-11"></span></p>
<p>On pourrait se demander pour quelle raison utiliser libglade car OCaml est un langage statiquement typé particulièrement sûr comparé à un fichier XML chargé dynamiquement et qui pourrait être modifié sans contrôle à tout moment. On pourrait argumenter qu&rsquo;il est bon de séparer le visuel de l&rsquo;interface et sa logique interne mais là encore le système de modules de OCaml est particulièrement bien adapté pour le <em>separation of concerns</em>.<br />
L&rsquo;intérêt indiscutable c&rsquo;est la flexibilité, en particulier l&rsquo;internationalisation est bien plus facile à réaliser que si elle était codée en dur. Et puis après tout la question n&rsquo;est pas là, c&rsquo;est à la mode, on peut le faire en Haskell, on peut le faire en OCaml, c&rsquo;est facile à faire et ça justifie bien un nouveau billet blog. </p>
<p>Mon fichier XML est en tous points identique à celui de <strong>Alp</strong> :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;?xml version=&quot;1.0&quot;?&gt; <br />
&lt;glade-interface&gt; &nbsp;<br />
&nbsp; &lt;!-- interface-requires gtk+ 2.16 --&gt; &nbsp;<br />
&nbsp; &lt;!-- interface-naming-policy project-wide --&gt; &nbsp;<br />
&nbsp; &lt;widget class=&quot;GtkWindow&quot; id=&quot;window1&quot;&gt; &nbsp;<br />
&nbsp; &lt;property name=&quot;title&quot; translatable=&quot;yes&quot;&gt;Hello, Developpez !&lt;/property&gt; &nbsp;<br />
&nbsp; &lt;property name=&quot;default_width&quot;&gt;400&lt;/property&gt; &nbsp;<br />
&nbsp; &lt;property name=&quot;default_height&quot;&gt;400&lt;/property&gt; &nbsp;<br />
&nbsp; &lt;child&gt; &nbsp;<br />
&nbsp; &lt;widget class=&quot;GtkButton&quot; id=&quot;yo&quot;&gt; &nbsp;<br />
&nbsp; &lt;property name=&quot;label&quot; translatable=&quot;yes&quot;&gt;Bonjour Developpez, comment vas-tu ? &nbsp;<br />
&nbsp;<br />
Je suis un programme OCaml qui utilise <br />
LablGtk2, le binding GTK+ pour OCaml. <br />
&nbsp;<br />
Clique pour fermer.&lt;/property&gt; &nbsp;<br />
&nbsp; &lt;property name=&quot;visible&quot;&gt;True&lt;/property&gt; &nbsp;<br />
&nbsp; &lt;property name=&quot;can_focus&quot;&gt;True&lt;/property&gt; &nbsp;<br />
&nbsp; &lt;property name=&quot;receives_default&quot;&gt;True&lt;/property&gt; &nbsp;<br />
&nbsp; &lt;/widget&gt; &nbsp;<br />
&nbsp; &lt;/child&gt; &nbsp;<br />
&nbsp; &lt;/widget&gt; &nbsp;<br />
&lt;/glade-interface&gt;</div></div>
<p>Faites attention à ce que la balise <strong>?xml</strong> soit bien sur la toute 1ière ligne du fichier sinon OCaml génèrera un avertissement et/ou une exception.</p>
<p>Le code source OCaml pour charger le XML et quitter quand l&rsquo;utilisateur clique sur le bouton : </p>
<pre>
let xml =
   Glade.create ~file:"hello.glade" ()
in let window = new GWindow.window
   (GtkWindow.Window.cast(Glade.get_widget xml "window1"))
in let button = new GButton.button
   (GtkButton.Button.cast(Glade.get_widget xml "yo")
in button#connect#clicked ~callback:
   (fun () -> print_endline "Bye"; window#destroy (); GMain.Main.quit ());
   window#show ();
   GMain.Main.main ()
</pre>
<p>La différence principale avec <strong>Gtk2Hs</strong>, hormis l&rsquo;absence de la <strong>do</strong>-notation, se situe au niveau du chargement et de la conversion.<br />
C&rsquo;est légèrement plus tortueux qu&rsquo;en Gtk2Hs, ça se fait en 3 étapes. C&rsquo;est dû à la couche orienté-objet de LablGtk.</p>
<ol>
<li> on charge le gadget à l&rsquo;aide de <em>Glade.get_widget</em>, on obtient un <em>Gtk.widget Gtk.obj</em></li>
<li> on converti ce <em>Gtk.widget Gtk.obj</em> en <em>Gtk.window Gtk.obj</em> à l&rsquo;aide de <em>GtkWindow.Window.cast</em> </li>
<li> ça ne s&rsquo;arrête pas là, il n&rsquo;est toujours pas possible d&rsquo;utiliser cette fenêtre avec les méthodes de LablGtk parce qu&rsquo;un <em>Gtk.window Gtk.obj</em> est une valeur mais pas un objet. il faut une deuxième conversion en un objet <em>GWindow.window</em>, en fait une instanciation réalisée par <strong>new GWindow.window</strong></li>
</ol>
<p>Voilà, ça n&rsquo;était pas sorcier mais comme il faut naviguer dans une doc hyper-texte touffue et avare en explication, la première fois c&rsquo;est toujours un peu déroutant.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Déclarations et motifs</title>
		<link>https://blog.developpez.com/damien-guichard/p8188/programmation-fonctionnelle/declarations_et_motifs</link>
		<comments>https://blog.developpez.com/damien-guichard/p8188/programmation-fonctionnelle/declarations_et_motifs#comments</comments>
		<pubDate>Mon, 12 Oct 2009 18:28:27 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Objective Caml]]></category>
		<category><![CDATA[Programmation fonctionnelle]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Motifs variable Comme vous le savez sans doute le let ne permet pas seulement de déclarer une nouvelle variable par exemple ici la variable m : let choose = function &#124; None -> None &#124; Some n -> let m = minimum n n.left in Some (m.key,m.item) Motifs simples Il permet aussi de déconstruire une valeur selon un motif comme ici la paire (m,l) : let rec delete_min t = match t.left with &#124; None [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><center><a href="http://caml.inria.fr/" target="_blank"><img src="http://caml.inria.fr//pub/logos/caml-inria-fr.128x58.gif"/></a></center></p>
<h3>Motifs variable</h3>
<p>Comme vous le savez sans doute le <strong>let</strong> ne permet pas seulement de déclarer une nouvelle variable par exemple ici la variable <em>m</em> : </p>
<pre>
  let choose = function
    | None -> None
    | Some n -> let m = minimum n n.left in Some (m.key,m.item)
</pre>
<h3>Motifs simples</h3>
<p>Il permet aussi de déconstruire une valeur selon un motif comme ici la paire <em>(m,l)</em> : </p>
<pre>
  let rec delete_min t = 
    match t.left with
    | None   -> t,t.right
    | Some n -> let m,l = delete_min n in m,Some {t with left = l}
</pre>
<p><span id="more-24"></span></p>
<p>Bien sûr le <strong>let</strong> n&rsquo;accepte qu&rsquo;un motif qui ne doit pas pouvoir échouer (on dit aussi <em>exhaustif</em>).<br />
Dans le cas contraire OCaml génère un avertissement et vous seriez bien avisé d&rsquo;utiliser un <strong>match</strong> afin de gérer tous les cas.<br />
La déconstruction par une variable <em>m</em> réussi toujours puisqu&rsquo;une variable est un motif universel (la variable _  n&rsquo;a rien de plus universel, elle est seulement plus anonyme).<br />
La déconstruction par un couple de variables <em>(m,l)</em> réussi toujours également puisqu&rsquo;une paire ne peut pas être autre chose qu&rsquo;un couple de valeurs.   </p>
<p>Là où le <strong>let</strong> ne fait plus l&rsquo;affaire c&rsquo;est sur un type union comme celui-ci :</p>
<pre>
type ast_val =
  | Val of int            (* offset *)
  | Array of int * int    (* offset, size of item *)
</pre>
<p>Qui dit qu&rsquo;une valeur est :</p>
<ul>
<li>ou bien une valeur positionnée à un certain offset</li>
<li>ou bien un tableau de valeurs (de même taille) positionné à un certain offset</li>
</ul>
<p>Dans le cas général, on utilise un <strong>match</strong> pour déconstruire les valeurs union.<br />
Cependant, il arrive qu&rsquo;un traitement ne dépende pas du constructeur mais d&rsquo;une information disponible dans tous les cas.</p>
<p>Par exemple ici on génère du code qui va placer l&rsquo;adresse d&rsquo;une certaine valeur dans un certain registre cpu : </p>
<pre>
  let rec eval_addr reg = function
    | Member(record,var) -> 
        eval_addr reg record;
        ( match var with
        | Var offset ->
            emit (Addr(reg,Offset(reg,offset)))
        | Array(offset,_) ->
            emit (Addr(reg,Offset(reg,offset))) )
    | ItemAt(vector,index,size) ->  
        eval_addr reg vector;
        eval_val (reg+1) index;
        emit (Addr(reg,Scale(reg,reg+1,size)))
</pre>
<p>Le code émit ne dépend que de l&rsquo;offset, il est le même que la valeur soit un tableau ou non.<br />
Distinguer les deux cas devient alors une nuisance, il y a répétition et de plus il faut parenthéser le <strong>match</strong> pour qu&rsquo;il ne capture pas le cas <em>ItemAt(vector,index,size)</em>. On peut faire plus agréable à l&rsquo;oeil.</p>
<h3>Motifs union</h3>
<p>L&rsquo;union d&rsquo;un motif a et d&rsquo;un motif b est un motif noté a | b qui accepte aussi bien le motif a que le motif b. (¹)<br />
Dans notre code on peut éviter la répétition en utilisant un motif union :</p>
<pre>
  ( match var with
  | Var offset | Array(offset,_) ->
      emit (Addr(reg,Offset(reg,offset))) )
</pre>
<p>En fait, puisqu&rsquo;on n&rsquo;a qu&rsquo;un seul motif exhaustif qui sert essentiellement à déclarer la variable <em>offset</em>, on peut carrément remplacer <strong>match</strong> par un <strong>let</strong> :                  </p>
<pre>
  let Var offset | Array(offset,_) = var
  in  emit (Addr(reg,Offset(reg,offset)))
</pre>
<p>(¹) il y a quelques contraintes sur les motifs a et b, ils doivent être de même type et déclarer le même ensemble de variables</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The art of the Propagator</title>
		<link>https://blog.developpez.com/damien-guichard/p8172/programmation-fonctionnelle/the_art_of_the_propagator</link>
		<comments>https://blog.developpez.com/damien-guichard/p8172/programmation-fonctionnelle/the_art_of_the_propagator#comments</comments>
		<pubDate>Thu, 08 Oct 2009 15:29:57 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Objective Caml]]></category>
		<category><![CDATA[Programmation fonctionnelle]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[À la lecture de The Art of the Propagator je me suis laissé convaincre que l&#8217;avenir de la programmation déclarative était dans la propagation logique. L&#8217;intérêt de la propagation c&#8217;est que le calcul monodirectionnel disparaît, le calcul devient multi-directionnel, la béta-réduction devient la béta-équivalence. Jusqu&#8217;à présent je m&#8217;étais toujours dit &#171;&#160;et alors, quel intérêt ?&#160;&#187;. C&#8217;est là que The Art of the Propagator apporte un argument de poids : le calcul monodirectionnel suppose un temps [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><center><a href="http://caml.inria.fr/" target="_blank"><img src="http://caml.inria.fr//pub/logos/caml-inria-fr.128x58.gif"/></a></center></p>
<p>À la lecture de <a href="http://web.mit.edu/~axch/www/phd-thesis.pdf" target="_blank">The Art of the Propagator</a> je me suis laissé convaincre que l&rsquo;avenir de la programmation déclarative était dans la propagation logique. L&rsquo;intérêt de la propagation c&rsquo;est que le calcul monodirectionnel disparaît, le calcul devient multi-directionnel, la béta-réduction devient la béta-équivalence.</p>
<p>Jusqu&rsquo;à présent je m&rsquo;étais toujours dit &laquo;&nbsp;et alors, quel intérêt ?&nbsp;&raquo;.<br />
C&rsquo;est là que <a href="http://web.mit.edu/~axch/www/phd-thesis.pdf" target="_blank">The Art of the Propagator</a> apporte un argument de poids :</p>
<ul>
<li>le calcul monodirectionnel suppose un temps fondamentalement linéaire, il y a un avant et un après la réduction</li>
<li>le parallélisme c&rsquo;est quand le temps n&rsquo;est plus linéaire</li>
<li>pourquoi chercher à recréer l&rsquo;illusion du temps linéaire alors qu&rsquo;il suffit de lever la restriction monodirectionnelle pour adopter le point de vue du parallélisme ?</li>
</ul>
<p><span id="more-23"></span></p>
<p>Ni une ni deux, installation presto de B-Prolog et petite traduction de l&rsquo;exemple tiré de <a href="http://web.mit.edu/~axch/www/phd-thesis.pdf" target="_blank">The Art of the Propagator</a> (le document d&rsquo;origine utilise des composants logiciels en Scheme à connecter comme pour une simulation de circuit électronique) : </p>
<pre>
temperature(F,C,K) :-
   C is (F - 32) * 5/9,
   K is C + 273.
</pre>
<p>J&rsquo;adore ce style complètement équationnel.   </p>
<p>Ce code peut convertir en degrés celsius et degrés en kelvins et même détecter une contradiction entre deux valeurs non convertibles :</p>
<pre>
| ?- temperature(77,C,K).
C = 25.0
K = 298.0
yes
| ?- temperature(45,C,298).
no
</pre>
<p>Malheureusement il semblerait que le calcul soit monodirectionnel, tout se passe comme si C était calculé à partir de F puis K à partir de C. Il m&rsquo;est imposible d&rsquo;obtenir une réponse sans fournir une valeur pour F :</p>
<pre>
| ?- temperature(F,25,K).
***  error(instantiation_error,b_EVAL_ARITH_cf/2)
| ?- temperature(F,C,298).
***  error(instantiation_error,b_EVAL_ARITH_cf/2)
</pre>
<p>Il y a sans doute une façon de le faire en Prolog mais j&rsquo;aurai aussi vite fait de l&rsquo;écrire en Caml.</p>
<p>Les circuits sont composés de constantes entières, de variables (réliées à un ou deux composants), d&rsquo;entrées (limitées à 2), de sorties et d&rsquo;opérateurs :</p>
<pre>
type expr =
  | Int of int
  | Var1 of int * expr
  | Var2 of int * expr * expr
  | Input1 of operator
  | Input2 of operator
  | Output of operator 
and operator =
  &lt;input1:evaluator; input2:evaluator; output:evaluator&gt;
  * expr * expr * expr
and evaluator =
  (expr -> int option) -> expr -> expr -> int option 
</pre>
<p>L&rsquo;évaluateur <em>eval</em> calcule la valeur d&rsquo;un point du circuit.<br />
Le paramètre <em>m</em> est un marqueur destiné à éviter les parcours en boucle.<br />
Etant donné l&rsquo;environnement <em>env</em>, il suffira d&rsquo;appeler l&rsquo;évaluateur sur un noeud contenant une variable pour connaître sa valeur.</p>
<p>Cette façon de faire me paraît plus dénotationnelle que la version Scheme de <a href="http://web.mit.edu/~axch/www/phd-thesis.pdf" target="_blank">The Art of the Propagator</a> qui donne une sémantique opérationnelle à l&rsquo;aide d&rsquo;un scheduler.</p>
<p>Remarquez que du fait que mon circuit est paramétré par un environnement j&rsquo;obtiens gratuitement un moyen d&rsquo;abstraction sur les circuits propagateurs. Je n&rsquo;aurai qu&rsquo;à créer un nouvel environnement pour changer les 3 températures alors qu&rsquo;avec la version Scheme il faut explicitement reconnecter un nouveau circuit (les températures sont immutables).</p>
<pre>
let rec eval env m = function
  | Var1(n,e1) ->
      ( match List.nth env n,eval env m e1 with
      | None,x | x,None -> x
      | Some x,Some y when x = y -> Some x
      | _ -> failwith "incoherence" )
  | Var2(n,e1,e2) ->
      ( match List.nth env n,eval env m e1,eval env m e2 with
      | x,None,None | None,x,None | None,None,x -> x
      | None,Some y,Some z when y = z -> Some z
      | Some x,None,Some z when x = z -> Some x
      | Some x,Some y,None when x = y -> Some y
      | Some x,Some y,Some z when x = y &amp;&amp; y = z -> Some z
      | _ -> failwith "incoherence" )
  | Int n ->
      Some n
  | Input1 p ->
      if p == m then None else 
      let op,a,b,c = p in op#input1 (eval env p) b c
  | Input2 p ->
      if p == m then None else 
      let op,a,b,c = p in op#input2 (eval env p) a c
  | Output p ->
      if p == m then None else 
      let op,a,b,c = p in op#output (eval env p) a b
</pre>
<p>La classe operation nous permettra d&rsquo;ajouter facilement des opérateurs.      </p>
<pre>
class operation fa fb fc =
  let result f x y =
    match x,y with
    | Some x,Some y -> Some(f x y)
    | _ -> None
  in
  object
    method input1 : evaluator =
      fun eval b c -> result fa (eval c) (eval b)
    method input2 : evaluator = 
      fun eval a c -> result fb (eval c) (eval a)
    method output : evaluator = 
      fun eval a b -> result fc (eval a) (eval b)  
  end
</pre>
<p>Trois opérateurs élémentaires:</p>
<pre>
let add = new operation ( - ) ( - ) ( + )
and mul = new operation ( / ) ( / ) ( * ) 
and sub = new operation ( + ) (fun c a -> a - c) ( - ) 
</pre>
<p>La construction du circuit : </p>
<pre>
let t =
  let
  rec f = Var1(0,Output add32)
  and c = Var2(1,Input2 mul9,Input2 add273)
  and k = Var1(2,Output add273)
  and add32  = add, Int 32, Input2 mul5, f
  and mul5   = mul, Int 5, Input2 add32, Output mul9
  and mul9   = mul, Int 9, c, Output mul5
  and add273 = add, Int 273, c, k
  in
  object
    method fahrenheit = f
    method celsius = c
    method kelvin = k
  end
</pre>
<p>L&rsquo;objet renvoyé en résultat fourni un accès direct aux trois sondes de température du circuit.  </p>
<p>Une rédéfinition de <em>eval</em> pour démarrer avec un marqueur fantôche : </p>
<pre>
let eval env expr =
  let start = add,Int 0,Int 0,Int 0
  in  eval env start expr
</pre>
<p>Des exemples d&rsquo;inférence :   </p>
<pre>
# eval [None;Some 25;None]  t#fahrenheit;;
- : int option = Some 77
# eval [Some 77;None;None]  t#celsius;;
- : int option = Some 25
# eval [Some 77;None;None]  t#kelvin;;
- : int option = Some 298
# eval [None;None;Some 298] t#fahrenheit;;
- : int option = Some 77
</pre>
<p>Cohérence et incohérence de valeurs multiples :</p>
<pre>
# eval [None;Some 25;Some 298] t#fahrenheit;;
- : int option = Some 77
# eval [None;Some 23;Some 298] t#fahrenheit;;
Exception: Failure "incoherence".
</pre>
<p>En ajoutant un peu de sucre syntaxique il devrait être possible de déclarer <em>temperature</em> comme en Prolog.</p>
<p>Avec le code de <em>eval</em> on a déjà l&rsquo;élément de base pour écrire un interpréteur pour un langage déclaratif multi-directionnel.<br />
Cependant on irait pas très loin car <a href="http://web.mit.edu/~axch/www/phd-thesis.pdf" target="_blank">The Art of the Propagator</a> ne dit pas comment exploiter la multi-directionnalité sur des exemples plus convaincants. Peut-on par exemple exécuter un dérivateur formel &laquo;&nbsp;à l&rsquo;envers&nbsp;&raquo; pour obtenir un intégrateur formel par propagation ?<br />
Si oui, comment ? Si non, pourquoi ?</p>
<p>Au bout du compte la thèse est avare en exemples consistants et se contente de conjecturer de possibles champs d&rsquo;application, notamment dans les domaines des TMS (Truth aintenance Systems), de la recherche dirigée par les dépendances et la FRP (Functional reactive Programming).</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Plus d&#8217;arguments avec l&#8217;application partielle</title>
		<link>https://blog.developpez.com/damien-guichard/p8150/programmation-fonctionnelle/plus_d_arguments_avec_l_application_part</link>
		<comments>https://blog.developpez.com/damien-guichard/p8150/programmation-fonctionnelle/plus_d_arguments_avec_l_application_part#comments</comments>
		<pubDate>Sun, 04 Oct 2009 19:12:29 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Objective Caml]]></category>
		<category><![CDATA[Programmation fonctionnelle]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Dans mon petit exemple de ce jour on va utiliser l&#8217;application partielle pour faire l&#8217;inverse de ce qu&#8217;on en fait habituellement. Au lieu d&#8217;éliminer un argument on va au contraire en ajouter un supplémentaire. L&#8217;idée de départ c&#8217;est que, étant donné un opérateur diadic (supposé associatif à droite), nous l&#8217;appliquons deux fois pour pouvoir opérer sur 3 arguments: let triadic op a b c = op a (op b c);; Une application partielle sert à [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><center><a href="http://caml.inria.fr/" target="_blank"><img src="http://caml.inria.fr//pub/logos/caml-inria-fr.128x58.gif"/></a></center></p>
<p>Dans mon petit exemple de ce jour on va utiliser l&rsquo;application partielle pour faire l&rsquo;inverse de ce qu&rsquo;on en fait habituellement. Au lieu d&rsquo;éliminer un argument on va au contraire en ajouter un supplémentaire.</p>
<p>L&rsquo;idée de départ c&rsquo;est que, étant donné un opérateur diadic (supposé associatif à droite), nous l&rsquo;appliquons deux fois pour pouvoir opérer sur 3 arguments: </p>
<pre>
let triadic op a b c = op a (op b c);; 
</pre>
<p>Une application partielle sert à produire un nouvel opérateur triadic:</p>
<pre>
let plus_plus = triadic (+);; 
</pre>
<p>Comme on a appliqué un argument, la fonction plus_plus ne prend plus que 3 arguments au lieu de 4 pour la fonction triadic.</p>
<p>C&rsquo;est un point de vue, en tout cas c&rsquo;est celui mis en avant dans nombre d&rsquo;introductions à la programmation fonctionnelle. </p>
<p>Un autre point de vue, sans doute plus approprié ici, c&rsquo;est que la fonction plus_plus prend 3 arguments au lieu de 2 pour la fonction (+) :</p>
<pre>
plus_plus 1 2 3;;  
- : int = 6
</pre>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Plus d&#8217;arguments sans application partielle</title>
		<link>https://blog.developpez.com/damien-guichard/p8151/programmation-fonctionnelle/plus_d_arguments_sans_application_partie</link>
		<comments>https://blog.developpez.com/damien-guichard/p8151/programmation-fonctionnelle/plus_d_arguments_sans_application_partie#comments</comments>
		<pubDate>Sun, 04 Oct 2009 19:27:49 +0000</pubDate>
		<dc:creator><![CDATA[SpiceGuid]]></dc:creator>
				<category><![CDATA[Objective Caml]]></category>
		<category><![CDATA[Programmation fonctionnelle]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Encore plus fort! Plus d&#8217;arguments mais cette fois-ci sans application partielle! Vous conviendrez aisément que cette fonction ne prend qu&#8217;un seul argument: let id x = x Hé bien je peux, mesdames et messieurs, devant vos yeux ébahis, lui appliquer 4 arguments: # id id (+) 1 2;; - : int = 3 Et c&#8217;est bien typé! Incroyable, ils sont fous ces programmeurs fonctionnels!]]></description>
				<content:encoded><![CDATA[<p><center><a href="http://caml.inria.fr/" target="_blank"><img src="http://caml.inria.fr//pub/logos/caml-inria-fr.128x58.gif"/></a></center></p>
<p>Encore plus fort!<br />
Plus d&rsquo;arguments mais cette fois-ci sans application partielle!</p>
<p>Vous conviendrez aisément que cette fonction ne prend qu&rsquo;un seul argument:</p>
<pre>
let id x = x 
</pre>
<p>Hé bien je peux, mesdames et messieurs, devant vos yeux ébahis, lui appliquer 4 arguments:</p>
<pre>
# id id (+) 1 2;;
- : int = 3
</pre>
<p>Et c&rsquo;est bien typé!<br />
Incroyable, ils sont fous ces programmeurs fonctionnels!</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
