her.esy.fun/src/Scratch/fr/blog/Haskell-the-Hard-Way/index.html

2390 lines
237 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>YBlog - Haskell comme un vrai!</title>
<meta name="keywords" content="Haskell, programming, functional, tutorial" />
<link rel="shortcut icon" type="image/x-icon" href="../../../../Scratch/img/favicon.ico" />
<link rel="stylesheet" type="text/css" href="../../../../Scratch/css/brutalist.css" />
<link rel="stylesheet" type="text/css" href="/css/legacy.css" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="apple-touch-icon" href="../../../../Scratch/img/about/FlatAvatar@2x.png" />
<!--[if lt IE 9]>
<script src="http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js"></script>
<![endif]-->
<!-- IndieAuth -->
<link href="https://twitter.com/yogsototh" rel="me">
<link href="https://github.com/yogsototh" rel="me">
<link href="mailto:yann.esposito@gmail.com" rel="me">
<link rel="pgpkey" href="../../../../pubkey.txt">
</head>
<body lang="fr" class="article">
<div id="content">
<div id="header">
<div id="choix">
<span id="choixlang">
<a href="../../../../Scratch/en/blog/Haskell-the-Hard-Way/">Anglais</a>
</span>
<span class="tomenu"><a href="#navigation">↓ Menu ↓</a></span>
<span class="flush"></span>
</div>
</div>
<div id="titre">
<h1>Haskell comme un vrai!</h1>
<h2>Haskell à s'en faire griller les neurones</h2>
</div>
<div class="flush"></div>
<div id="afterheader" class="article">
<div class="corps">
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/magritte_pleasure_principle.jpg" alt="Magritte pleasure principle" />
</div>
<div class="intro">
<p><span class="sc"><abbr title="Trop long; pas lu">tlpl</abbr>: </span> Un tutoriel très court mais très dense pour apprendre Haskell.</p>
<p>Merci à&nbsp;:</p>
<ul>
<li><a href="https://plus.google.com/u/0/113751420744109290534">Oleg Taykalo</a> vous pouvez trouver une traduction russe ici: <a href="http://habrahabr.ru/post/152889/">Partie 1</a> <em>&amp;</em> <a href="http://habrahabr.ru/post/153383/">Partie 2</a> ;</li>
<li><a href="https://sillybytes.net">Daniel Campoverde</a> pour la version Espagnole : <a href="https://sillybytes.net/2016/06/aprende-haskell-rapido-y-dificil_29.html">Aprende Haskell rápido y difícil</a> ;</li>
<li><a href="http://github.com/joom">Joomy Korkut</a> pour sa traduction en Turc: <a href="https://github.com/joom/zor-yoldan-haskell">Zor Yoldan Haskell</a></li>
<li><a href="https://github.com/lepereceval">lepereceval</a> pour sa traduction française que je nai pas eu le courage de faire !</li>
<li><a href="https://github.com/youqad">Younesse Kaddar</a> et <a href="https://github.com/mmenestret">Menestret Martin</a> pour les corrections de styles et dorthographes.</li>
</ul>
<blockquote>
<center>
<hr style="width:30%;float:left;border-color:#CCCCD0;margin-top:1em" />
<span class="sc"><b>Table of Content</b></span>
<hr style="width:30%;float:right;border-color:#CCCCD0;margin-top:1em" />
</center>
<div class="toc">
<ul>
<li><a href="#introduction">Introduction</a>
<ul>
<li><a href="#install">Installation</a></li>
<li><a href="#don-t-be-afraid">Ne soyez pas effrayés!</a></li>
<li><a href="#very-basic-haskell">Les bases de Haskell</a>
<ul>
<li><a href="#function-declaration">Déclaration de fonctions</a></li>
<li><a href="#a-type-example">Un exemple de type</a></li>
</ul></li>
</ul></li>
<li><a href="#essential-haskell">Notions essentielles</a>
<ul>
<li><a href="#notations">Notations</a>
<ul>
<li><a href="#arithmetic">Arithmétique</a></li>
<li><a href="#logic">Logique</a></li>
<li><a href="#powers">Puissances</a></li>
<li><a href="#lists">Listes</a></li>
<li><a href="#strings">Chaînes de caractères</a></li>
<li><a href="#tuples">Tuples</a></li>
<li><a href="#deal-with-parentheses">Traiter avec les parenthèses</a></li>
</ul></li>
<li><a href="#useful-notations-for-functions">Notations utiles pour les fonctions</a></li>
</ul></li>
<li><a href="#hard-part">La Partie Difficile</a>
<ul>
<li><a href="#functional-style">Le style fonctionnel</a>
<ul>
<li><a href="#higher-order-functions">Fonctions dordre supérieur</a></li>
</ul></li>
<li><a href="#types">Les types</a>
<ul>
<li><a href="#type-inference">Inférence de type</a></li>
<li><a href="#type-construction">Construction de types</a></li>
<li><a href="#recursive-type">Type récursif</a></li>
<li><a href="#trees">Les arbres</a></li>
</ul></li>
<li><a href="#infinite-structures">Structures infinies</a></li>
</ul></li>
<li><a href="#hell-difficulty-part">Partie de difficulté infernale</a>
<ul>
<li><a href="#deal-with-io">Soccuper de lE/S (IO)</a></li>
<li><a href="#io-trick-explained">Le truc des IO révélé</a></li>
<li><a href="#monads">Les monades</a>
<ul>
<li><a href="#maybe-monad">Maybe est une monade</a></li>
<li><a href="#the-list-monad">La monade List</a></li>
</ul></li>
</ul></li>
<li><a href="#appendix">Appendice</a>
<ul>
<li><a href="#more-on-infinite-tree">Revenons sur les arbres infinis</a></li>
</ul></li>
</ul>
</div>
</blockquote>
</div>
<div class="intro">
<p>Je pense vraiment que tous les développeurs devraient apprendre Haskell. Peut-être pas devenir des ninjas dHaskell, mais au moins savoir ce que ce langage a de particulier. Son apprentissage ouvre énormément lesprit.</p>
<p>La plupart des langages partagent les mêmes fondements&nbsp;:</p>
<ul>
<li>les variables</li>
<li>les boucles</li>
<li>les pointeurs<a href="#fn1" class="footnote-ref" id="fnref1"><sup>1</sup></a></li>
<li>les structures de données, les objets et les classes</li>
</ul>
<p>Haskell est très différent. Ce langage utilise des concepts dont je navais jamais entendu parler avant. Beaucoup de ces concepts pourront vous aider à devenir un meilleur développeur.</p>
<p>Plier son esprit à Haskell peut être difficile. Ce le fut pour moi. Dans cet article, jessaye de fournir les informations qui mont manquées lors de mon apprentissage.</p>
<p>Cet article sera certainement difficile à suivre. Mais cest voulu. Il ny a pas de raccourci pour apprendre Haskell. Cest difficile. Mais je pense que cest une bonne chose. Cest entre autres parce quHaskell est difficile quil est intéressant.</p>
<p>La manière conventionnelle dapprendre Haskell est de lire deux livres. Dabord <a href="http://haskell.fr/lyah/">“Learn You a Haskell”</a> et ensuite <a href="http://www.realworldhaskell.org">“Real World Haskell”</a>. Je pense aussi que cest la bonne manière de sy prendre. Mais apprendre même un tout petit peu dHaskell est presque impossible sans se plonger réellement dans ces livres.</p>
<p>Cet article fait un résumé très dense et rapide des aspects majeurs dHaskell. Jy ai aussi rajouté des informations qui mont manqué pendant lapprentissage de ce langage.</p>
<p>Pour les francophones : je suis désolé. Je nai pas eu le courage de tout retraduire en français. Sachez cependant que si vous êtes plusieurs à insister, je ferai certainement leffort de traduire larticle en entier. Et si vous vous sentez davoir une bonne âme je ne suis pas contre un peu daide. Les sources de cet article sont sur <a href="http://github.com/yogsototh/learn_haskell.git">github</a>.</p>
<p>Cet article contient cinq parties&nbsp;:</p>
<ul>
<li>Introduction : un exemple rapide pour montrer quHaskell peut être facile.</li>
<li>Les bases dHaskell : La syntaxe et des notions essentielles</li>
<li>Partie difficile :
<ul>
<li>Style fonctionnel : un exemple progressif, du style impératif au style fonctionnel ;</li>
<li>Types : la syntaxe et un exemple darbre binaire ;</li>
<li>Structure infinie : manipulons un arbre infini !</li>
</ul></li>
<li>Partie de difficulté infernale :
<ul>
<li>Utiliser les IO : un exemple très minimal ;</li>
<li>Le truc des IO révélé : les détails cachés dIO qui mont manqués</li>
<li>Les monades : incroyable à quel point on peut généraliser</li>
</ul></li>
<li>Appendice :
<ul>
<li>Revenons sur les arbres infinis : une discussion plus mathématique sur la manipulation darbres infinis.</li>
</ul></li>
</ul>
<blockquote>
Note: Chaque fois que vous voyez un séparateur avec un nom de fichier se terminant par <code>lhs</code>, vous pouvez cliquer sur le nom de fichier et télécharger le fichier. Si vous sauvegardez le fichier sour le nom <code>filename.lhs</code>, vous pouvez lexécuter avec :
<pre>
runhaskell filename.lhs
</pre>
<p>Certains ne marcheront pas, mais la majorité vous donneront un résultat. Vous devriez voir un lien juste en dessous.</p>
</blockquote>
</div>
<hr />
<p><a href="code/01_basic/10_Introduction/00_hello_world.lhs" class="cut">01_basic/10_Introduction/<strong>00_hello_world.lhs</strong></a></p>
<h2 id="introduction">
Introduction
</h2>
<h3 id="install">
Installation
</h3>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/Haskell-logo.png" alt />
</div>
<p>Aujourdhuil je considère que la manière la plus aisée dinstaller Haskell est dutiliser <a href="https://haskellstack.org"><code>stack</code></a>.</p>
<p>Il y a dautres manières dinstaller Haskell sur votre système, vous pouvez en savoir plus en visitant <a href="https://haskell.org">haskell.org</a> ou <a href="https://haskell-lang.org">haskell-lang.org</a></p>
<p>Outils:</p>
<ul>
<li><code>ghc</code>: Compilateur similaire à gcc pour le langage <code>C</code>.</li>
<li><code>ghci</code>: Console Haskell interactive (Read-Eval-Print Loop)</li>
<li><code>runhaskell</code>: Exécuter un programme sans le compiler. Pratique mais très lent comparé aux programmes compilés.</li>
</ul>
<h3 id="don-t-be-afraid">
Ne soyez pas effrayés!
</h3>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/munch_TheScream.jpg" alt="The Scream" />
</div>
<p>Beaucoup de livres/articles sur Haskell commencent par présenter des formules ésotériques (Algorithmes de tri rapide, suite de Fibonacci, etc…). Je ferai lexact opposé En premier lieu je ne vous montrerai pas les super-pouvoirs dHaskell. Je vais commencer par les similarités avec les autres langages de programmation. Commençons par lindispensable “Hello World!”.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb1-1" title="1">main <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">&quot;Hello World!&quot;</span></a></code></pre></div>
</div>
<p>Pour lexécuter, vous pouvez enregistrer ce code dans un fichier <code>hello.hs</code> et:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode zsh"><code class="sourceCode zsh"><a class="sourceLine" id="cb2-1" title="1">~ runhaskell ./hello.hs</a>
<a class="sourceLine" id="cb2-2" title="2">Hello World!</a></code></pre></div>
<p>ou si vous utilisez <code>stack</code> lancez dabord <code>stack setup</code> et ensuite&nbsp;:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode zsh"><code class="sourceCode zsh"><a class="sourceLine" id="cb3-1" title="1">~ stack runhaskell ./hello.hs</a>
<a class="sourceLine" id="cb3-2" title="2">Hello World!</a></code></pre></div>
<p>Vous pouvez également télécharger la source Haskell littérale. Vous devriez voir un lien juste au dessus du titre de lintroduction. Téléchargez ce fichier en tant que <code>00_hello_world.lhs</code> et:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode zsh"><code class="sourceCode zsh"><a class="sourceLine" id="cb4-1" title="1">~ runhaskell 00_hello_world.lhs</a>
<a class="sourceLine" id="cb4-2" title="2">Hello World!</a></code></pre></div>
<p><a href="code/01_basic/10_Introduction/00_hello_world.lhs" class="cut">01_basic/10_Introduction/<strong>00_hello_world.lhs</strong> </a></p>
<hr />
<p><a href="code/01_basic/10_Introduction/10_hello_you.lhs" class="cut">01_basic/10_Introduction/<strong>10_hello_you.lhs</strong></a></p>
<p>Maintenant, un programme qui demande votre nom et répond “Hello” suivit du nom que vous avez entré:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb5-1" title="1">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb5-2" title="2"> <span class="fu">print</span> <span class="st">&quot;What is your name?&quot;</span></a>
<a class="sourceLine" id="cb5-3" title="3"> name <span class="ot">&lt;-</span> <span class="fu">getLine</span></a>
<a class="sourceLine" id="cb5-4" title="4"> <span class="fu">print</span> (<span class="st">&quot;Hello &quot;</span> <span class="op">++</span> name <span class="op">++</span> <span class="st">&quot;!&quot;</span>)</a></code></pre></div>
</div>
<p>Premièrement, comparons ce code avec ceux de quelques langages de programmation impératif:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><a class="sourceLine" id="cb6-1" title="1"><span class="co"># Python</span></a>
<a class="sourceLine" id="cb6-2" title="2"><span class="bu">print</span> <span class="st">&quot;What is your name?&quot;</span></a>
<a class="sourceLine" id="cb6-3" title="3">name <span class="op">=</span> <span class="bu">raw_input</span>()</a>
<a class="sourceLine" id="cb6-4" title="4"><span class="bu">print</span> <span class="st">&quot;Hello </span><span class="sc">%s</span><span class="st">!&quot;</span> <span class="op">%</span> name</a></code></pre></div>
<div class="sourceCode" id="cb7"><pre class="sourceCode ruby"><code class="sourceCode ruby"><a class="sourceLine" id="cb7-1" title="1"><span class="co"># Ruby</span></a>
<a class="sourceLine" id="cb7-2" title="2">puts <span class="st">&quot;What is your name?&quot;</span></a>
<a class="sourceLine" id="cb7-3" title="3">name = gets.chomp</a>
<a class="sourceLine" id="cb7-4" title="4">puts <span class="st">&quot;Hello </span><span class="ot">#{</span>name<span class="ot">}</span><span class="st">!&quot;</span></a></code></pre></div>
<div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb8-1" title="1"><span class="co">// In C</span></a>
<a class="sourceLine" id="cb8-2" title="2"><span class="pp">#include </span><span class="im">&lt;stdio.h&gt;</span></a>
<a class="sourceLine" id="cb8-3" title="3"><span class="dt">int</span> main (<span class="dt">int</span> argc, <span class="dt">char</span> **argv) {</a>
<a class="sourceLine" id="cb8-4" title="4"> <span class="dt">char</span> name[<span class="dv">666</span>]; <span class="co">// &lt;- An Evil Number!</span></a>
<a class="sourceLine" id="cb8-5" title="5"> <span class="co">// What if my name is more than 665 character long?</span></a>
<a class="sourceLine" id="cb8-6" title="6"> printf(<span class="st">&quot;What is your name?</span><span class="sc">\n</span><span class="st">&quot;</span>);</a>
<a class="sourceLine" id="cb8-7" title="7"> scanf(<span class="st">&quot;%s&quot;</span>, name);</a>
<a class="sourceLine" id="cb8-8" title="8"> printf(<span class="st">&quot;Hello %s!</span><span class="sc">\n</span><span class="st">&quot;</span>, name);</a>
<a class="sourceLine" id="cb8-9" title="9"> <span class="cf">return</span> <span class="dv">0</span>;</a>
<a class="sourceLine" id="cb8-10" title="10">}</a></code></pre></div>
<p>La structure est la même, mais il y a quelques différences de syntaxe. La partie principale de ce tutoriel sera consacrée à expliquer cela.</p>
<p>En Haskell il y a une fonction <code>main</code> tous les objets ont un type. Le type de <code>main</code> est <code>IO ()</code>. Cela veut dire que <code>main</code> causera des effets secondaires.</p>
<p>Rappelez-vous just que Haskell peut ressembler énormément aux principaux langages impératifs.</p>
<p><a href="code/01_basic/10_Introduction/10_hello_you.lhs" class="cut">01_basic/10_Introduction/<strong>10_hello_you.lhs</strong> </a></p>
<hr />
<p><a href="code/01_basic/10_Introduction/20_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>20_very_basic.lhs</strong></a></p>
<h3 id="very-basic-haskell">
Les bases de Haskell
</h3>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/picasso_owl.jpg" alt="Picasso minimal owl" />
</div>
<p>Avant de continuer, vous devez êtres avertis à propos de propriétés essentielles de Haskell.</p>
<p><em>Fonctionnel</em></p>
<p>Haskell est un langage fonctionnel Si vous avez déjà travaillé avec un langage impératif, vous devrez apprendre beaucoup de nouvelles choses. Heureusement beaucoup de ces nouveaux concepts vous aidera à programmer même dans un langage impératif.</p>
<p><em>Typage Statique Intelligent</em></p>
<p>Au lieu de bloquer votre chemin comme en <code>C</code>, <code>C++</code> ou <code>Java</code>, le système de typage est ici pour vous aider.</p>
<p><em>Pureté</em></p>
<p>Généralement vos fonctions ne modifieront rien du le monde extérieur. Cela veut dire quelles ne peuvent pas modifier la valeur dune variable, lire du texte entré par un utilisateur, écrire sur lécran, lancer un missile. Dun autre coté, avoir un code parallèle devient très facile. Haskell rend très clair où les effets apparaissent et où le code est pur. De plus, il devient beaucoup plus aisé de raisonner sur son programme. La majorité des bugs seront évités dans les parties pures de votre programme.</p>
<p>En outre, les fonctions pures suivent une loi fondamentale en Haskell:</p>
<blockquote>
<p>Appliquer une fonction avec les mêmes paramètres retourne toujours la même valeur.</p>
</blockquote>
<p><em>Paresse</em></p>
<p>La paresse par défaut est un choix de conception de langage très rare. Par défaut, Haskell évalue quelque chose seulement lorsque cela est nécessaire. En conséquence, cela fournit un moyen très élégant de manipuler des structures infinies, par exemple.</p>
<p>Un dernier avertissement sur comment vous devriez lire le code Haskell. Pour moi, cest comme lire des papiers scientifiques. Quelques parties sont très claires, mais quand vous voyez une formule, concentrez-vous dessus et lisez plus lentement. De plus, lorsque vous apprenez Haskell, cela nimporte <em>vraiment</em> pas si vous ne comprenez pas les détails syntaxiques. Si vous voyez un <code>&gt;&gt;=</code>, <code>&lt;$&gt;</code>, <code>&lt;-</code> ou nimporte quel symbole bizarre, ignorez-les et suivez le déroulement du code.</p>
<h4 id="function-declaration">
Déclaration de fonctions
</h4>
<p>Vous avez déjà dû déclarer des fonctions comme cela:</p>
<p>En <code>C</code>:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb9-1" title="1"><span class="dt">int</span> f(<span class="dt">int</span> x, <span class="dt">int</span> y) {</a>
<a class="sourceLine" id="cb9-2" title="2"> <span class="cf">return</span> x*x + y*y;</a>
<a class="sourceLine" id="cb9-3" title="3">}</a></code></pre></div>
<p>En JavaScript:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode javascript"><code class="sourceCode javascript"><a class="sourceLine" id="cb10-1" title="1"><span class="kw">function</span> <span class="at">f</span>(x<span class="op">,</span>y) <span class="op">{</span></a>
<a class="sourceLine" id="cb10-2" title="2"> <span class="cf">return</span> x<span class="op">*</span>x <span class="op">+</span> y<span class="op">*</span>y<span class="op">;</span></a>
<a class="sourceLine" id="cb10-3" title="3"><span class="op">}</span></a></code></pre></div>
<p>En Python:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode python"><code class="sourceCode python"><a class="sourceLine" id="cb11-1" title="1"><span class="kw">def</span> f(x,y):</a>
<a class="sourceLine" id="cb11-2" title="2"> <span class="cf">return</span> x<span class="op">*</span>x <span class="op">+</span> y<span class="op">*</span>y</a></code></pre></div>
<p>En Ruby:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode ruby"><code class="sourceCode ruby"><a class="sourceLine" id="cb12-1" title="1"><span class="kw">def</span> f(x,y)</a>
<a class="sourceLine" id="cb12-2" title="2"> x*x + y*y</a>
<a class="sourceLine" id="cb12-3" title="3"><span class="kw">end</span></a></code></pre></div>
<p>En Scheme:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode scheme"><code class="sourceCode scheme"><a class="sourceLine" id="cb13-1" title="1">(<span class="ex">define</span><span class="fu"> </span>(f x y)</a>
<a class="sourceLine" id="cb13-2" title="2"> (<span class="op">+</span> (* x x) (* y y)))</a></code></pre></div>
<p>Finalement, la manière de faire de Haskell est:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb14-1" title="1">f x y <span class="ot">=</span> x<span class="op">*</span>x <span class="op">+</span> y<span class="op">*</span>y</a></code></pre></div>
<p>Très propre. Aucune parenthèse, aucun <code>def</code>.</p>
<p>Noubliez pas, Haskell utilise beaucoup les fonctions et les types. Cest très facile de les définir. La syntaxe a été particulièrement réfléchie pour ces objets.</p>
<h4 id="a-type-example">
Un exemple de type
</h4>
<p>Même si ce nest pas obligatoire, les informations de type pour les fonctions sont habituellement déclarées explicitement. Ce nest pas indispensable car le compilateur est suffisamment intelligent pour le déduire à votre place. Cependant, cest une bonne idée car cela montre bien lintention du développeur et facilite la compréhension.</p>
<p>Jouons un peu. On déclare le type en utilisant <code>::</code></p>
<div class="codehighlight">
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb15-1" title="1"><span class="ot"> f ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb15-2" title="2"> f x y <span class="ot">=</span> x<span class="op">*</span>x <span class="op">+</span> y<span class="op">*</span>y</a>
<a class="sourceLine" id="cb15-3" title="3"></a>
<a class="sourceLine" id="cb15-4" title="4"> main <span class="ot">=</span> <span class="fu">print</span> (f <span class="dv">2</span> <span class="dv">3</span>)</a></code></pre></div>
</div>
<pre><code>~ runhaskell 20_very_basic.lhs
13</code></pre>
<p><a href="code/01_basic/10_Introduction/20_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>20_very_basic.lhs</strong> </a></p>
<hr />
<p><a href="code/01_basic/10_Introduction/21_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>21_very_basic.lhs</strong></a></p>
<p>Maintenant essayez</p>
<div class="codehighlight">
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb17-1" title="1"><span class="ot">f ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb17-2" title="2">f x y <span class="ot">=</span> x<span class="op">*</span>x <span class="op">+</span> y<span class="op">*</span>y</a>
<a class="sourceLine" id="cb17-3" title="3"></a>
<a class="sourceLine" id="cb17-4" title="4">main <span class="ot">=</span> <span class="fu">print</span> (f <span class="fl">2.3</span> <span class="fl">4.2</span>)</a></code></pre></div>
</div>
<p>Vous devriez avoir cette erreur:</p>
<pre><code>21_very_basic.lhs:6:23:
No instance for (Fractional Int)
arising from the literal `4.2'
Possible fix: add an instance declaration for (Fractional Int)
In the second argument of `f', namely `4.2'
In the first argument of `print', namely `(f 2.3 4.2)'
In the expression: print (f 2.3 4.2)</code></pre>
<p>Le problème est que <code>4.2</code> nest pas de type <code>Int</code> (<em>NDT: Il nest pas un entier</em>)</p>
<p><a href="code/01_basic/10_Introduction/21_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>21_very_basic.lhs</strong> </a></p>
<hr />
<p><a href="code/01_basic/10_Introduction/22_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>22_very_basic.lhs</strong></a></p>
<p>La soulution: ne déclarez pas de type pour <code>f</code> pour le moment et laissez Haskell inférer le type le plus général pour nous:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb19-1" title="1">f x y <span class="ot">=</span> x<span class="op">*</span>x <span class="op">+</span> y<span class="op">*</span>y</a>
<a class="sourceLine" id="cb19-2" title="2"></a>
<a class="sourceLine" id="cb19-3" title="3">main <span class="ot">=</span> <span class="fu">print</span> (f <span class="fl">2.3</span> <span class="fl">4.2</span>)</a></code></pre></div>
</div>
<p>Maintenant, ça marche! Heureursement, nous navons pas à déclarer un nouvelle fonction pour chaque type différent. Par exemple, en <code>C</code>, vous auriez dû déclarer un fonction pour <code>int</code>, pour <code>float</code>, pour <code>long</code>, pour <code>double</code>, etc…</p>
<p>Mais quel type devons nous déclarer? Pour découvrir le type que Haskell a trouvé pour nous, lançons ghci:</p>
<pre><span class="low">
%</span> ghci<span class="low"><code>
GHCi, version 7.0.4: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude></code></span> let f x y = x*x + y*y
<span class="low"><code>Prelude></code></span> :type f
<code>f :: Num a => a -> a -> a</code>
</pre>
<p>Hein? Quel ce type étrange?</p>
<pre><code>Num a =&gt; a -&gt; a -&gt; a</code></pre>
<p>Premièrement, concentrons-nous sur la partie de droite: <code>a -&gt; a -&gt; a</code>. Pour le comprendre, regardez cette liste dexemples progressifs:</p>
<table>
<colgroup>
<col style="width: 20%" />
<col style="width: 80%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Le type écrit</th>
<th style="text-align: left;">Son sens</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><code>Int</code></td>
<td style="text-align: left;">Le type <code>Int</code></td>
</tr>
<tr class="even">
<td style="text-align: left;"><code>Int -&gt; Int</code></td>
<td style="text-align: left;">Le type de la fonction qui prend un <code>Int</code> et retourne un <code>Int</code></td>
</tr>
<tr class="odd">
<td style="text-align: left;"><code>Float -&gt; Int</code></td>
<td style="text-align: left;">Le type de la fonction qui prend un <code>Float</code> et retourne un <code>Int</code></td>
</tr>
<tr class="even">
<td style="text-align: left;"><code>a -&gt; Int</code></td>
<td style="text-align: left;">Le type de la fonction qui prend nimporte quel type de variable et retourne un <code>Int</code></td>
</tr>
<tr class="odd">
<td style="text-align: left;"><code>a -&gt; a</code></td>
<td style="text-align: left;">Le type de la fonction qui prend nimporte quel type <code>a</code> et retourne une variable du même type <code>a</code></td>
</tr>
<tr class="even">
<td style="text-align: left;"><code>a -&gt; a -&gt; a</code></td>
<td style="text-align: left;">Le type de la fonction qui prend deux arguments de nimporte quel type<code>a</code> et retourne une variable de type <code>a</code></td>
</tr>
</tbody>
</table>
<p>Dans le type <code>a -&gt; a -&gt; a</code>, la lettre <code>a</code> est une <em>variable de type</em>. Cela signifie que <code>f</code> est une fonction avec deux arguments et que les deux arguments et le résultat ont le même type. La variable de type <code>a</code> peut prendre de nombreuses valeurs différentes Par exemple <code>Int</code>, <code>Integer</code>, <code>Float</code></p>
<p>Donc à la place davoir un type forcé comme en <code>C</code> et de devoir déclarer une fonction pour <code>int</code>, <code>long</code>, <code>float</code>, <code>double</code>, etc., nous déclarons une seule fonction comme dans un langage typé de façon dynamique.</p>
<p>Cest parfois appelé le polymorphisme paramétrique. Cest aussi appelé avoir un gâteau et le manger.</p>
<p>Généralement <code>a</code> peut être de nimporte quel type, par exemple un <code>String</code> ou un <code>Int</code>, mais aussi des types plus complexes comme <code>Trees</code>, dautres fonctions, etc. Mais ici notre type est préfixé par <code>Num a =&gt;</code>.</p>
<p><code>Num</code> est une <em>classe de type</em>. Une classe de type peut être comprise comme un ensemble de types <code>Num</code> contient seulement les types qui se comportent comme des nombres. Plus précisement, <code>Num</code> est une classe qui contient des types qui implémentent une liste spécifique de fonctions, en particulier <code>(+)</code> et <code>(*)</code>.</p>
<p>Les classes de types sont une structure de langage très puissante. Nous pouvons faire des trucs incroyablement puissants avec. Nous verrons cela plus tard.</p>
<p>Finalement, <code>Num a =&gt; a -&gt; a -&gt; a</code> signifie:</p>
<p>soit <code>a</code> un type qui appartient à la classe <code>Num</code>. Cest une fonction qui prend une variable de type <code>a</code> et retourne une fonction de type <code>(a -&gt; a)</code></p>
<p>Oui, cest étrange. En fait, en Haskell aucune fonction ne prend réellement deux arguments. Au lieu de cela toutes les fonctions nont quun argument unique. Mais nous retiendrons que prendre deux arguments est équivalent à nen prendre quun et à retourner une fonction qui prend le second argument en paramètre.</p>
<p>Plus précisement <code>f 3 4</code> est équivalent à <code>(f 3) 4</code>. Remarque: <code>f 3</code> est une fonction:</p>
<pre><code>f :: Num a =&gt; a -&gt; a -&gt; a
g :: Num a =&gt; a -&gt; a
g = f 3
g y ⇔ 3*3 + y*y</code></pre>
<p>Une autre notation existe pour les fonctions. La notation lambda nous autorise à créer des fonctions sans leur assigner un nom. On les appelle des fonctions anonymes. nous aurions donc pu écrire:</p>
<pre><code>g = \y -&gt; 3*3 + y*y</code></pre>
<p>Le <code>\</code> esst utilisé car il ressemble à un <code>λ</code> et est un caractère ASCII.</p>
<p>Si vous nêtes pas habitué à la programmation fonctionnelle, votre cerveau devrait commencer à chauffer Il est temps de faire une vraie application.</p>
<p><a href="code/01_basic/10_Introduction/22_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>22_very_basic.lhs</strong> </a></p>
<hr />
<p><a href="code/01_basic/10_Introduction/23_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>23_very_basic.lhs</strong></a></p>
<p>Mais juste avant cela, nous devrions vérifier que le système de type marche comme nous le supposons:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb23-1" title="1"><span class="ot">f ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb23-2" title="2">f x y <span class="ot">=</span> x<span class="op">*</span>x <span class="op">+</span> y<span class="op">*</span>y</a>
<a class="sourceLine" id="cb23-3" title="3"></a>
<a class="sourceLine" id="cb23-4" title="4">main <span class="ot">=</span> <span class="fu">print</span> (f <span class="dv">3</span> <span class="fl">2.4</span>)</a></code></pre></div>
</div>
<p>Cela fonctionne, car <code>3</code> est une représentation valide autant pour les nombres fractionnaires comme Float que pour les entiers. Comme <code>2.4</code> est un nombre fractionnaire, <code>3</code> est interprété comme une autre nombre fractionnaire</p>
<p><a href="code/01_basic/10_Introduction/23_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>23_very_basic.lhs</strong> </a></p>
<hr />
<p><a href="code/01_basic/10_Introduction/24_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>24_very_basic.lhs</strong></a></p>
<p>Si nous forçons notre fonction à travailler avec des types différents, le test échouera:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb24"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb24-1" title="1"><span class="ot">f ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb24-2" title="2">f x y <span class="ot">=</span> x<span class="op">*</span>x <span class="op">+</span> y<span class="op">*</span>y</a>
<a class="sourceLine" id="cb24-3" title="3"></a>
<a class="sourceLine" id="cb24-4" title="4"><span class="ot">x ::</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb24-5" title="5">x <span class="ot">=</span> <span class="dv">3</span></a>
<a class="sourceLine" id="cb24-6" title="6"><span class="ot">y ::</span> <span class="dt">Float</span></a>
<a class="sourceLine" id="cb24-7" title="7">y <span class="ot">=</span> <span class="fl">2.4</span></a>
<a class="sourceLine" id="cb24-8" title="8"><span class="co">-- won't work because type x ≠ type y</span></a>
<a class="sourceLine" id="cb24-9" title="9">main <span class="ot">=</span> <span class="fu">print</span> (f x y)</a></code></pre></div>
</div>
<p>Le compilateur se plaint. Les deux paramètres doivent avoir le même type.</p>
<p>Si vous pensez que cest une mauvaise idée et que le compilateur devrait faire la transformation depuis un type à un autre pour vous, vous devriez vraiment regarder cette vidéo géniale (et amusante): <a href="https://www.destroyallsoftware.com/talks/wat">WAT</a> (<em>NDT: En Anglais</em>)</p>
<p><a href="code/01_basic/10_Introduction/24_very_basic.lhs" class="cut">01_basic/10_Introduction/<strong>24_very_basic.lhs</strong> </a></p>
<h2 id="essential-haskell">
Notions essentielles
</h2>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/kandinsky_gugg.jpg" alt="Kandinsky Gugg" />
</div>
<p>Je vous suggère de seulement survoler cette partie Pensez-y seulement comme à une référence. Haskell a beaucoup de caractèristiques Il manque beaucoup dinformations ici. Revenz ici si la notation vous semble étrange.</p>
<p>Jutilise le symbole <code></code> pour signifier que deux expressions sont équivalentes. Cest une notation extérieure, <code></code> nexiste pas en Haskell. Je vais aussi utiliser le symoble <code></code> quelle est la valeur que retourne une fonction.</p>
<h3 id="notations">
Notations
</h3>
<h5 id="arithmetic">
Arithmétique
</h5>
<pre><code>3 + 2 * 6 / 3 ⇔ 3 + ((2*6)/3)</code></pre>
<h5 id="logic">
Logique
</h5>
<pre><code>True || False ⇒ True
True &amp;&amp; False ⇒ False
True == False ⇒ False
True /= False ⇒ True (/=) est l'opérateur pour &quot;différent de&quot;</code></pre>
<h5 id="powers">
Puissances
</h5>
<pre><code>x^n pour n un entier (comprenez Int ou Integer)
x**y pour y tout type de nombre (Float par exemple)</code></pre>
<p><code>Integer</code> na aucune limite à part la capacité de votre machine:</p>
<pre><code>4^103
102844034832575377634685573909834406561420991602098741459288064</code></pre>
<p>Yeah! Et aussi les nombres rationnels! Mais vous avez besoin dimporter le module <code>Data.Ratio</code></p>
<pre><code>$ ghci
....
Prelude&gt; :m Data.Ratio
Data.Ratio&gt; (11 % 15) * (5 % 3)
11 % 9</code></pre>
<h5 id="lists">
Listes
</h5>
<pre><code>[] ⇔ liste vide
[1,2,3] ⇔ Liste d'entiers
[&quot;foo&quot;,&quot;bar&quot;,&quot;baz&quot;] ⇔ Liste de chaînes de caractères
1:[2,3] ⇔ [1,2,3], (:) ajoute un élément au début
1:2:[] ⇔ [1,2]
[1,2] ++ [3,4] ⇔ [1,2,3,4], (++) concaténation de deux listes
[1,2,3] ++ [&quot;foo&quot;] ⇔ ERREUR String ≠ Integral
[1..4] ⇔ [1,2,3,4]
[1,3..10] ⇔ [1,3,5,7,9]
[2,3,5,7,11..100] ⇔ ERREUR! Je ne suis pas si intelligent!
[10,9..1] ⇔ [10,9,8,7,6,5,4,3,2,1]</code></pre>
<h5 id="strings">
Chaînes de caractères
</h5>
<p>En Haskell les chaînes de caractères sont des listes de <code>Char</code>.</p>
<pre><code>'a' :: Char
&quot;a&quot; :: [Char]
&quot;&quot; ⇔ []
&quot;ab&quot; ⇔ ['a','b'] ⇔ 'a':&quot;b&quot; ⇔ 'a':['b'] ⇔ 'a':'b':[]
&quot;abc&quot;&quot;ab&quot;++&quot;c&quot;</code></pre>
<blockquote>
<p><em>Remarque</em>: Dans un vrai code vous nutiliserez pas des listes de char pour représenter du texte. Vous utiliserez plus souvent <code>Data.Text</code> à la place. Si vous voulez représenter un chapelet de caractères ASCII, vous utiliserez <code>Data.ByteString</code>.</p>
</blockquote>
<h5 id="tuples">
Tuples
</h5>
<p>Le type dun couple est <code>(a,b)</code>. Les éléments dun tuple peuvent avoir des types différents.</p>
<pre><code>-- tous ces tuples sont valides
(2,&quot;foo&quot;)
(3,'a',[2,3])
((2,&quot;a&quot;),&quot;c&quot;,3)
fst (x,y) ⇒ x
snd (x,y) ⇒ y
fst (x,y,z) ⇒ ERROR: fst :: (a,b) -&gt; a
snd (x,y,z) ⇒ ERROR: snd :: (a,b) -&gt; b</code></pre>
<h5 id="deal-with-parentheses">
Traiter avec les parenthèses
</h5>
<p>Pour enlever des parenthèses vous pouvez utiliser deux fonctions: <code>($)</code> et <code>(.)</code>.</p>
<pre><code>-- Par défaut:
f g h x ⇔ (((f g) h) x)
-- le $ remplace les parenthèses depuis le $
-- jusqu'à la fin de l'expression.
f g $ h x ⇔ f g (h x) ⇔ (f g) (h x)
f $ g h x ⇔ f (g h x) ⇔ f ((g h) x)
f $ g $ h x ⇔ f (g (h x))
-- (.) permet de faire des compositions de fonctions
(f . g) x ⇔ f (g x)
(f . g . h) x ⇔ f (g (h x))</code></pre>
<hr />
<p><a href="code/01_basic/20_Essential_Haskell/10a_Functions.lhs" class="cut">01_basic/20_Essential_Haskell/<strong>10a_Functions.lhs</strong></a></p>
<h3 id="useful-notations-for-functions">
Notations utiles pour les fonctions
</h3>
<p>Juste un mémo:</p>
<pre><code>x :: Int ⇔ x est de type Int
x :: a ⇔ x peut être de n'importe quel type
x :: Num a =&gt; a ⇔ x peut être de n'importe quel type a
tant qu' a appartient à la classe de type Num
f :: a -&gt; b ⇔ f est une fonction qui prend un a et retourne un b
f :: a -&gt; b -&gt; c ⇔ f est une fonction qui prend un a et retourne un (b→c)
f :: (a -&gt; b) -&gt; c ⇔ f est une fonction qui prend un (a→b) et retourne un c</code></pre>
<p>Rappelez-vous que définir le type dune fonction avant sa déclaration nest pas obligatoire. Haskell infère le type le plus général pour vous. Mais cest considéré comme une bonne pratique.</p>
<p><em>Notation Infixée</em></p>
<div class="codehighlight">
<div class="sourceCode" id="cb35"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb35-1" title="1"><span class="ot">square ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb35-2" title="2">square x <span class="ot">=</span> x<span class="op">^</span><span class="dv">2</span></a></code></pre></div>
</div>
<p>Remarquez que <code>^</code> utilise une notation infixée. Pour chaque opérateur infixe il y a une notation préfixée associée. Vous devez juste lécrire entre parenthèses.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb36"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb36-1" title="1">square' x <span class="ot">=</span> (<span class="op">^</span>) x <span class="dv">2</span></a>
<a class="sourceLine" id="cb36-2" title="2"></a>
<a class="sourceLine" id="cb36-3" title="3">square'' x <span class="ot">=</span> (<span class="op">^</span><span class="dv">2</span>) x</a></code></pre></div>
</div>
<p>Nous pouvons enlever le <code>x</code> dans les parties de gauche et de droite! On appelle cela la η-réduction</p>
<div class="codehighlight">
<div class="sourceCode" id="cb37"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb37-1" title="1">square''' <span class="ot">=</span> (<span class="op">^</span><span class="dv">2</span>)</a></code></pre></div>
</div>
<p>Rmarquez qu nous pouvons déclarer des fonctions avec <code>'</code> dans leur nom. Exemples:</p>
<blockquote>
<p><code>square</code><code>square'</code><code>square''</code><code>square'''</code></p>
</blockquote>
<p><em>Tests</em></p>
<p>Une implémentation de la fonction absolue.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb38"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb38-1" title="1"><span class="ot">absolute ::</span> (<span class="dt">Ord</span> a, <span class="dt">Num</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb38-2" title="2">absolute x <span class="ot">=</span> <span class="kw">if</span> x <span class="op">&gt;=</span> <span class="dv">0</span> <span class="kw">then</span> x <span class="kw">else</span> <span class="op">-</span>x</a></code></pre></div>
</div>
<p>Remarque: la notation de Haskell pour le <code>if .. then .. else</code> ressemble plus à lopérateur <code>¤?¤:¤</code> en C. Le <code>else</code> est obligatoire.</p>
<p>Une version équivalente:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb39"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb39-1" title="1">absolute' x</a>
<a class="sourceLine" id="cb39-2" title="2"> <span class="op">|</span> x <span class="op">&gt;=</span> <span class="dv">0</span> <span class="ot">=</span> x</a>
<a class="sourceLine" id="cb39-3" title="3"> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="op">-</span>x</a></code></pre></div>
</div>
<blockquote>
<p>Avertissement: lindentation est <em>importante</em> en Haskell. Comme en Python, une mauvaise indentation peut détruire votre code!</p>
</blockquote>
<div style="display:none">
<div class="codehighlight">
<div class="sourceCode" id="cb40"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb40-1" title="1">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb40-2" title="2"> <span class="fu">print</span> <span class="op">$</span> square <span class="dv">10</span></a>
<a class="sourceLine" id="cb40-3" title="3"> <span class="fu">print</span> <span class="op">$</span> square' <span class="dv">10</span></a>
<a class="sourceLine" id="cb40-4" title="4"> <span class="fu">print</span> <span class="op">$</span> square'' <span class="dv">10</span></a>
<a class="sourceLine" id="cb40-5" title="5"> <span class="fu">print</span> <span class="op">$</span> square''' <span class="dv">10</span></a>
<a class="sourceLine" id="cb40-6" title="6"> <span class="fu">print</span> <span class="op">$</span> absolute <span class="dv">10</span></a>
<a class="sourceLine" id="cb40-7" title="7"> <span class="fu">print</span> <span class="op">$</span> absolute (<span class="op">-</span><span class="dv">10</span>)</a>
<a class="sourceLine" id="cb40-8" title="8"> <span class="fu">print</span> <span class="op">$</span> absolute' <span class="dv">10</span></a>
<a class="sourceLine" id="cb40-9" title="9"> <span class="fu">print</span> <span class="op">$</span> absolute' (<span class="op">-</span><span class="dv">10</span>)</a></code></pre></div>
</div>
</div>
<p><a href="code/01_basic/20_Essential_Haskell/10a_Functions.lhs" class="cut">01_basic/20_Essential_Haskell/<strong>10a_Functions.lhs</strong> </a></p>
<h2 id="hard-part">
La Partie Difficile
</h2>
<p>La partie difficile peut maintenant commencer.</p>
<h3 id="functional-style">
Le style fonctionnel
</h3>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/hr_giger_biomechanicallandscape_500.jpg" alt="Biomechanical Landscape by H.R. Giger" />
</div>
<p>Dans cette section, je vais vous donner un court exemple de limpressionante capacité de remaniement de Haskell. Nous allons sélectionner un problème et le résoudre à la manière dun langage impératif standard. Ensuite, je ferais évoluer le code. Le résultat final sera plus élégant et plus facile à adapter.</p>
<p>résolvons les problèmes suivants:</p>
<blockquote>
<p>Soit une liste dentiers, retourner la somme des nombres pairs de cette liste.</p>
<p>exemple: <code>[1,2,3,4,5] ⇒ 2 + 4 ⇒ 6</code></p>
</blockquote>
<p>Pour montrer les différences entre les approches fonctionnelle et impérative, je vais commencer par donner la solution impérative (en JavaScript):</p>
<div class="sourceCode" id="cb41"><pre class="sourceCode javascript"><code class="sourceCode javascript"><a class="sourceLine" id="cb41-1" title="1"><span class="kw">function</span> <span class="at">evenSum</span>(list) <span class="op">{</span></a>
<a class="sourceLine" id="cb41-2" title="2"> <span class="kw">var</span> result <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></a>
<a class="sourceLine" id="cb41-3" title="3"> <span class="cf">for</span> (<span class="kw">var</span> i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op">&lt;</span> <span class="va">list</span>.<span class="at">length</span> <span class="op">;</span> i<span class="op">++</span>) <span class="op">{</span></a>
<a class="sourceLine" id="cb41-4" title="4"> <span class="cf">if</span> (list[i] <span class="op">%</span> <span class="dv">2</span> <span class="op">==</span><span class="dv">0</span>) <span class="op">{</span></a>
<a class="sourceLine" id="cb41-5" title="5"> result <span class="op">+=</span> list[i]<span class="op">;</span></a>
<a class="sourceLine" id="cb41-6" title="6"> <span class="op">}</span></a>
<a class="sourceLine" id="cb41-7" title="7"> <span class="op">}</span></a>
<a class="sourceLine" id="cb41-8" title="8"> <span class="cf">return</span> result<span class="op">;</span></a>
<a class="sourceLine" id="cb41-9" title="9"><span class="op">}</span></a></code></pre></div>
<p>En Haskell, en revanche, nous navons pas de variables ou un boucle <code>for</code>. Une des solutions pour parvenir au même résultat sans boucles est dutiliser la récursion.</p>
<blockquote>
<p><em>Remarque</em>: La récursion est souvent perçue comme lente dans les langages impératifs. Mais ce nest généralement pas le cas en programmation fonctionnelle. La plupart du temps Haskell gérera les fonctions récursives efficacement.</p>
</blockquote>
<p>Voici la version <code>C</code> de la fonction récursive. Remarquez que je suppose que la liste dint fini avec la première valeur <code>0</code>.</p>
<div class="sourceCode" id="cb42"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb42-1" title="1"><span class="dt">int</span> evenSum(<span class="dt">int</span> *list) {</a>
<a class="sourceLine" id="cb42-2" title="2"> <span class="cf">return</span> accumSum(<span class="dv">0</span>,list);</a>
<a class="sourceLine" id="cb42-3" title="3">}</a>
<a class="sourceLine" id="cb42-4" title="4"></a>
<a class="sourceLine" id="cb42-5" title="5"><span class="dt">int</span> accumSum(<span class="dt">int</span> n, <span class="dt">int</span> *list) {</a>
<a class="sourceLine" id="cb42-6" title="6"> <span class="dt">int</span> x;</a>
<a class="sourceLine" id="cb42-7" title="7"> <span class="dt">int</span> *xs;</a>
<a class="sourceLine" id="cb42-8" title="8"> <span class="cf">if</span> (*list == <span class="dv">0</span>) { <span class="co">// if the list is empty</span></a>
<a class="sourceLine" id="cb42-9" title="9"> <span class="cf">return</span> n;</a>
<a class="sourceLine" id="cb42-10" title="10"> } <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb42-11" title="11"> x = list[<span class="dv">0</span>]; <span class="co">// let x be the first element of the list</span></a>
<a class="sourceLine" id="cb42-12" title="12"> xs = list+<span class="dv">1</span>; <span class="co">// let xs be the list without x</span></a>
<a class="sourceLine" id="cb42-13" title="13"> <span class="cf">if</span> ( <span class="dv">0</span> == (x%<span class="dv">2</span>) ) { <span class="co">// if x is even</span></a>
<a class="sourceLine" id="cb42-14" title="14"> <span class="cf">return</span> accumSum(n+x, xs);</a>
<a class="sourceLine" id="cb42-15" title="15"> } <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb42-16" title="16"> <span class="cf">return</span> accumSum(n, xs);</a>
<a class="sourceLine" id="cb42-17" title="17"> }</a>
<a class="sourceLine" id="cb42-18" title="18"> }</a>
<a class="sourceLine" id="cb42-19" title="19">}</a></code></pre></div>
<p>Gardez ce code à lesprit. Nous allons le traduire en Haskell. Premièrement,</p>
<div class="sourceCode" id="cb43"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb43-1" title="1"><span class="fu">even</span><span class="ot"> ::</span> <span class="dt">Integral</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Bool</span></a>
<a class="sourceLine" id="cb43-2" title="2"><span class="fu">head</span><span class="ot"> ::</span> [a] <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb43-3" title="3"><span class="fu">tail</span><span class="ot"> ::</span> [a] <span class="ot">-&gt;</span> [a]</a></code></pre></div>
<p><code>even</code> vérifie si un nombre est pair.</p>
<div class="sourceCode" id="cb44"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb44-1" title="1"><span class="fu">even</span><span class="ot"> ::</span> <span class="dt">Integral</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Bool</span></a>
<a class="sourceLine" id="cb44-2" title="2"><span class="fu">even</span> <span class="dv">3</span> <span class="ot"></span> <span class="dt">False</span></a>
<a class="sourceLine" id="cb44-3" title="3"><span class="fu">even</span> <span class="dv">2</span> <span class="ot"></span> <span class="dt">True</span></a></code></pre></div>
<p><code>head</code> retourne le premier élément dune liste:</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb45-1" title="1"><span class="fu">head</span><span class="ot"> ::</span> [a] <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb45-2" title="2"><span class="fu">head</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="ot"></span> <span class="dv">1</span></a>
<a class="sourceLine" id="cb45-3" title="3"><span class="fu">head</span> [] <span class="ot"></span> <span class="dt">ERROR</span></a></code></pre></div>
<p><code>tail</code> retourne tous les éléments dune liste, sauf le premier:</p>
<div class="sourceCode" id="cb46"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb46-1" title="1"><span class="fu">tail</span><span class="ot"> ::</span> [a] <span class="ot">-&gt;</span> [a]</a>
<a class="sourceLine" id="cb46-2" title="2"><span class="fu">tail</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="ot"></span> [<span class="dv">2</span>,<span class="dv">3</span>]</a>
<a class="sourceLine" id="cb46-3" title="3"><span class="fu">tail</span> [<span class="dv">3</span>] <span class="ot"></span> []</a>
<a class="sourceLine" id="cb46-4" title="4"><span class="fu">tail</span> [] <span class="ot"></span> <span class="dt">ERREUR</span></a></code></pre></div>
<p>Remarquez que pour toute liste non-vide <code>l</code>, <code>l ⇔ (head l):(tail l)</code></p>
<hr />
<p><a href="code/02_Hard_Part/11_Functions.lhs" class="cut">02_Hard_Part/<strong>11_Functions.lhs</strong></a></p>
<p>La première solution en Haskell. La fonction <code>evenSum</code> retourne la somme de tous les nombres pairs dune liste:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb47"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb47-1" title="1"><span class="co">-- Version 1</span></a>
<a class="sourceLine" id="cb47-2" title="2"><span class="ot">evenSum ::</span> [<span class="dt">Integer</span>] <span class="ot">-&gt;</span> <span class="dt">Integer</span></a>
<a class="sourceLine" id="cb47-3" title="3"></a>
<a class="sourceLine" id="cb47-4" title="4">evenSum l <span class="ot">=</span> accumSum <span class="dv">0</span> l</a>
<a class="sourceLine" id="cb47-5" title="5"></a>
<a class="sourceLine" id="cb47-6" title="6">accumSum n l <span class="ot">=</span> <span class="kw">if</span> l <span class="op">==</span> []</a>
<a class="sourceLine" id="cb47-7" title="7"> <span class="kw">then</span> n</a>
<a class="sourceLine" id="cb47-8" title="8"> <span class="kw">else</span> <span class="kw">let</span> x <span class="ot">=</span> <span class="fu">head</span> l</a>
<a class="sourceLine" id="cb47-9" title="9"> xs <span class="ot">=</span> <span class="fu">tail</span> l</a>
<a class="sourceLine" id="cb47-10" title="10"> <span class="kw">in</span> <span class="kw">if</span> <span class="fu">even</span> x</a>
<a class="sourceLine" id="cb47-11" title="11"> <span class="kw">then</span> accumSum (n<span class="op">+</span>x) xs</a>
<a class="sourceLine" id="cb47-12" title="12"> <span class="kw">else</span> accumSum n xs</a></code></pre></div>
</div>
<p>Pour tester une fonction nous pouvons utiliser <code>ghci</code>:</p>
<pre>
% ghci
<span class="low">GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude&gt;</span> :load 11_Functions.lhs
<span class="low">[1 of 1] Compiling Main ( 11_Functions.lhs, interpreted )
Ok, modules loaded: Main.
*Main&gt;</span> evenSum [1..5]
6
</pre>
<p>Voici un exemple dexécution<a href="#fn2" class="footnote-ref" id="fnref2"><sup>2</sup></a>:</p>
<pre>
*Main> evenSum [1..5]
accumSum 0 [1,2,3,4,5]
<span class="yellow">1 est impair</span>
accumSum 0 [2,3,4,5]
<span class="yellow">2 est pair</span>
accumSum (0+2) [3,4,5]
<span class="yellow">3 est impair</span>
accumSum (0+2) [4,5]
<span class="yellow">4 est pair</span>
accumSum (0+2+4) [5]
<span class="yellow">5 est impair</span>
accumSum (0+2+4) []
<span class="yellow">l == []</span>
0+2+4
0+6
6
</pre>
<p>En venant dun langage impératif, tout devrait vous sembler juste. En fait, beaucoup de choses peuvent être améliorées ici. Tout dabord, nous pouvons généraliser le type.</p>
<div class="sourceCode" id="cb48"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb48-1" title="1"><span class="ot">evenSum ::</span> <span class="dt">Integral</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> a</a></code></pre></div>
<div style="display:none">
<div class="codehighlight">
<div class="sourceCode" id="cb49"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb49-1" title="1">main <span class="ot">=</span> <span class="kw">do</span> <span class="fu">print</span> <span class="op">$</span> evenSum [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</a></code></pre></div>
</div>
</div>
<p><a href="code/02_Hard_Part/11_Functions.lhs" class="cut">02_Hard_Part/<strong>11_Functions.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/12_Functions.lhs" class="cut">02_Hard_Part/<strong>12_Functions.lhs</strong></a></p>
<p>Ensuite, nous pouvons utiliser des sous-fonctions grâce à <code>where</code> et <code>let</code>. Ansi, notre fonction <code>accumSum</code> ne polluera pas le <em>namespace</em> de notre module</p>
<div class="codehighlight">
<div class="sourceCode" id="cb50"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb50-1" title="1"><span class="co">-- Version 2</span></a>
<a class="sourceLine" id="cb50-2" title="2"><span class="ot">evenSum ::</span> <span class="dt">Integral</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb50-3" title="3"></a>
<a class="sourceLine" id="cb50-4" title="4">evenSum l <span class="ot">=</span> accumSum <span class="dv">0</span> l</a>
<a class="sourceLine" id="cb50-5" title="5"> <span class="kw">where</span> accumSum n l <span class="ot">=</span></a>
<a class="sourceLine" id="cb50-6" title="6"> <span class="kw">if</span> l <span class="op">==</span> []</a>
<a class="sourceLine" id="cb50-7" title="7"> <span class="kw">then</span> n</a>
<a class="sourceLine" id="cb50-8" title="8"> <span class="kw">else</span> <span class="kw">let</span> x <span class="ot">=</span> <span class="fu">head</span> l</a>
<a class="sourceLine" id="cb50-9" title="9"> xs <span class="ot">=</span> <span class="fu">tail</span> l</a>
<a class="sourceLine" id="cb50-10" title="10"> <span class="kw">in</span> <span class="kw">if</span> <span class="fu">even</span> x</a>
<a class="sourceLine" id="cb50-11" title="11"> <span class="kw">then</span> accumSum (n<span class="op">+</span>x) xs</a>
<a class="sourceLine" id="cb50-12" title="12"> <span class="kw">else</span> accumSum n xs</a></code></pre></div>
</div>
<div style="display:none">
<div class="codehighlight">
<div class="sourceCode" id="cb51"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb51-1" title="1">main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> evenSum [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</a></code></pre></div>
</div>
</div>
<p><a href="code/02_Hard_Part/12_Functions.lhs" class="cut">02_Hard_Part/<strong>12_Functions.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/13_Functions.lhs" class="cut">02_Hard_Part/<strong>13_Functions.lhs</strong></a></p>
<p>Puis on utilise le <em>pattern matching</em></p>
<div class="codehighlight">
<div class="sourceCode" id="cb52"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb52-1" title="1"><span class="co">-- Version 3</span></a>
<a class="sourceLine" id="cb52-2" title="2">evenSum l <span class="ot">=</span> accumSum <span class="dv">0</span> l</a>
<a class="sourceLine" id="cb52-3" title="3"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb52-4" title="4"> accumSum n [] <span class="ot">=</span> n</a>
<a class="sourceLine" id="cb52-5" title="5"> accumSum n (x<span class="op">:</span>xs) <span class="ot">=</span></a>
<a class="sourceLine" id="cb52-6" title="6"> <span class="kw">if</span> <span class="fu">even</span> x</a>
<a class="sourceLine" id="cb52-7" title="7"> <span class="kw">then</span> accumSum (n<span class="op">+</span>x) xs</a>
<a class="sourceLine" id="cb52-8" title="8"> <span class="kw">else</span> accumSum n xs</a></code></pre></div>
</div>
<p>Quest ce que le <em>pattern matching</em> ? Il sagit dutiliser des valeurs au lieu de noms de paramètres généraux.</p>
<p>Au lieu décrire: <code>foo l = if l == [] then &lt;x&gt; else &lt;y&gt;</code> Vous écrivez tout simplement&nbsp;:</p>
<div class="sourceCode" id="cb53"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb53-1" title="1">foo [] <span class="ot">=</span> <span class="op">&lt;</span>x<span class="op">&gt;</span></a>
<a class="sourceLine" id="cb53-2" title="2">foo l <span class="ot">=</span> <span class="op">&lt;</span>y<span class="op">&gt;</span></a></code></pre></div>
<p>Mais le <em>pattern matching</em> peut aller encore plus loin. Il est également capable dinspecter les données internes dun valeur complexe. Nous pouvons ainsi remplacer</p>
<div class="sourceCode" id="cb54"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb54-1" title="1">foo l <span class="ot">=</span> <span class="kw">let</span> x <span class="ot">=</span> <span class="fu">head</span> l</a>
<a class="sourceLine" id="cb54-2" title="2"> xs <span class="ot">=</span> <span class="fu">tail</span> l</a>
<a class="sourceLine" id="cb54-3" title="3"> <span class="kw">in</span> <span class="kw">if</span> <span class="fu">even</span> x</a>
<a class="sourceLine" id="cb54-4" title="4"> <span class="kw">then</span> foo (n<span class="op">+</span>x) xs</a>
<a class="sourceLine" id="cb54-5" title="5"> <span class="kw">else</span> foo n xs</a></code></pre></div>
<p>par</p>
<div class="sourceCode" id="cb55"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb55-1" title="1">foo (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">if</span> <span class="fu">even</span> x</a>
<a class="sourceLine" id="cb55-2" title="2"> <span class="kw">then</span> foo (n<span class="op">+</span>x) xs</a>
<a class="sourceLine" id="cb55-3" title="3"> <span class="kw">else</span> foo n xs</a></code></pre></div>
<p>Cest une caractéristique très utile. Notre code est ainsi plus concis et plus facile à lire.</p>
<div style="display:none">
<div class="codehighlight">
<div class="sourceCode" id="cb56"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb56-1" title="1">main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> evenSum [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</a></code></pre></div>
</div>
</div>
<p><a href="code/02_Hard_Part/13_Functions.lhs" class="cut">02_Hard_Part/<strong>13_Functions.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/14_Functions.lhs" class="cut">02_Hard_Part/<strong>14_Functions.lhs</strong></a></p>
<p>Avec Haskell, nous pouvons simplifier les défitions des fonctions en les <em>η-réduisant</em> . Par exemple, au lieu décrire:</p>
<div class="sourceCode" id="cb57"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb57-1" title="1">f x <span class="ot">=</span> (expression) x</a></code></pre></div>
<p>Nous pouvons écrire</p>
<div class="sourceCode" id="cb58"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb58-1" title="1">f <span class="ot">=</span> expression</a></code></pre></div>
<p>Utilisons cette méthode pour retirer le <code>l</code>:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb59"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb59-1" title="1"><span class="co">-- Version 4</span></a>
<a class="sourceLine" id="cb59-2" title="2"><span class="ot">evenSum ::</span> <span class="dt">Integral</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb59-3" title="3"></a>
<a class="sourceLine" id="cb59-4" title="4">evenSum <span class="ot">=</span> accumSum <span class="dv">0</span></a>
<a class="sourceLine" id="cb59-5" title="5"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb59-6" title="6"> accumSum n [] <span class="ot">=</span> n</a>
<a class="sourceLine" id="cb59-7" title="7"> accumSum n (x<span class="op">:</span>xs) <span class="ot">=</span></a>
<a class="sourceLine" id="cb59-8" title="8"> <span class="kw">if</span> <span class="fu">even</span> x</a>
<a class="sourceLine" id="cb59-9" title="9"> <span class="kw">then</span> accumSum (n<span class="op">+</span>x) xs</a>
<a class="sourceLine" id="cb59-10" title="10"> <span class="kw">else</span> accumSum n xs</a></code></pre></div>
</div>
<div style="display:none">
<div class="codehighlight">
<div class="sourceCode" id="cb60"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb60-1" title="1">main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> evenSum [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</a></code></pre></div>
</div>
</div>
<p><a href="code/02_Hard_Part/14_Functions.lhs" class="cut">02_Hard_Part/<strong>14_Functions.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/15_Functions.lhs" class="cut">02_Hard_Part/<strong>15_Functions.lhs</strong></a></p>
<h4 id="higher-order-functions">
Fonctions dordre supérieur
</h4>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/escher_polygon.png" alt="Escher" />
</div>
<p>Pour rendre les choses plus faciles, nous devrions utiliser des fonctions dordre supérieur. Ce sont des fonctions qui prennent des fonctions en paramètres</p>
<p>Voici quelques exemples:</p>
<div class="sourceCode" id="cb61"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb61-1" title="1"><span class="fu">filter</span><span class="ot"> ::</span> (a <span class="ot">-&gt;</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [a]</a>
<a class="sourceLine" id="cb61-2" title="2"><span class="fu">map</span><span class="ot"> ::</span> (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [b]</a>
<a class="sourceLine" id="cb61-3" title="3"><span class="fu">foldl</span><span class="ot"> ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> [b] <span class="ot">-&gt;</span> a</a></code></pre></div>
<p>Procédons par étapes.</p>
<div class="sourceCode" id="cb62"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb62-1" title="1"><span class="co">-- Version 5</span></a>
<a class="sourceLine" id="cb62-2" title="2">evenSum l <span class="ot">=</span> mysum <span class="dv">0</span> (<span class="fu">filter</span> <span class="fu">even</span> l)</a>
<a class="sourceLine" id="cb62-3" title="3"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb62-4" title="4"> mysum n [] <span class="ot">=</span> n</a>
<a class="sourceLine" id="cb62-5" title="5"> mysum n (x<span class="op">:</span>xs) <span class="ot">=</span> mysum (n<span class="op">+</span>x) xs</a></code></pre></div>
<p></p>
<div class="sourceCode" id="cb63"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb63-1" title="1"><span class="fu">filter</span> <span class="fu">even</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>] ⇔ [<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>,<span class="dv">8</span>,<span class="dv">10</span>]</a></code></pre></div>
<p>La fonction <code>filter</code> prend une fonction du type (<code>a -&gt; Bool</code>) et une liste de type <code>[a]</code>. Elle retourne une liste qui contient seulement les élements pour qui la fonction a retourné <code>True</code>.</p>
<p>La prochaine étape est dutiliser une autre technique pour accomplir la même chose quune boucle. Nous allons utiliser la fonction <code>foldl</code> pour accumuler une valeur au fur et à mesure que lon parcoure la liste. La fonction <code>foldl</code> capture un modèle de code général:</p>
<pre>
myfunc list = foo <span class="blue">initialValue</span> <span class="green">list</span>
foo accumulated [] = accumulated
foo tmpValue (x:xs) = foo (<span class="yellow">bar</span> tmpValue x) xs
</pre>
<p>Qui peut être remplacé par:</p>
<pre>
myfunc list = foldl <span class="yellow">bar</span> <span class="blue">initialValue</span> <span class="green">list</span>
</pre>
<p>Si vous souhaitez vraiment savoir comment la magie se produit, voici la définition de <code>foldl</code>:</p>
<div class="sourceCode" id="cb64"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb64-1" title="1"><span class="fu">foldl</span> f z [] <span class="ot">=</span> z</a>
<a class="sourceLine" id="cb64-2" title="2"><span class="fu">foldl</span> f z (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="fu">foldl</span> f (f z x) xs</a></code></pre></div>
<div class="sourceCode" id="cb65"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb65-1" title="1"><span class="fu">foldl</span> f z [x1,<span class="op">...</span>xn]</a>
<a class="sourceLine" id="cb65-2" title="2">⇔ f (<span class="op">...</span> (f (f z x1) x2) <span class="op">...</span>) xn</a></code></pre></div>
<p>Mais comme Haskell est paresseux, il névalue pas <code>(f z x)</code> et le met simplement dans la pile. Cest pourquoi on utilise généralement <code>foldl'</code>, une version <em>stricte</em> de <code>foldl</code>, Si vous ne comprenez pas encore ce que <em>paresseux</em> ou <em>strict</em> signifie, ne vous inquiétez pas, suivez le code comme si <code>foldl'</code> et <code>foldl</code> étaient identiques</p>
<p>Maintenant notre version de <code>evenSum</code> devient:</p>
<div class="sourceCode" id="cb66"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb66-1" title="1"><span class="co">-- Version 6</span></a>
<a class="sourceLine" id="cb66-2" title="2"><span class="co">-- foldl' n'est pas accessible par défaut</span></a>
<a class="sourceLine" id="cb66-3" title="3"><span class="co">-- nous devons l'importer depuis le module Data.List</span></a>
<a class="sourceLine" id="cb66-4" title="4"><span class="kw">import</span> <span class="dt">Data.List</span></a>
<a class="sourceLine" id="cb66-5" title="5">evenSum l <span class="ot">=</span> foldl' mysum <span class="dv">0</span> (<span class="fu">filter</span> <span class="fu">even</span> l)</a>
<a class="sourceLine" id="cb66-6" title="6"> <span class="kw">where</span> mysum acc value <span class="ot">=</span> acc <span class="op">+</span> value</a></code></pre></div>
<p>Nous pouvons aussi simplifier cela en utilisant une <em>lambda-notation</em>. Ainsi nous navons pas besoin de créer le nom temporaire <code>mySum</code>.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb67"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb67-1" title="1"><span class="co">-- Version 7</span></a>
<a class="sourceLine" id="cb67-2" title="2"><span class="co">-- Generally it is considered a good practice</span></a>
<a class="sourceLine" id="cb67-3" title="3"><span class="co">-- to import only the necessary function(s)</span></a>
<a class="sourceLine" id="cb67-4" title="4"><span class="kw">import</span> <span class="dt">Data.List</span> (foldl')</a>
<a class="sourceLine" id="cb67-5" title="5">evenSum l <span class="ot">=</span> foldl' (\x y <span class="ot">-&gt;</span> x<span class="op">+</span>y) <span class="dv">0</span> (<span class="fu">filter</span> <span class="fu">even</span> l)</a></code></pre></div>
</div>
<p>Et bien sûr, nous remarquons que</p>
<div class="sourceCode" id="cb68"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb68-1" title="1">(\x y <span class="ot">-&gt;</span> x<span class="op">+</span>y) ⇔ (<span class="op">+</span>)</a></code></pre></div>
<div style="display:none">
<div class="codehighlight">
<div class="sourceCode" id="cb69"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb69-1" title="1">main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> evenSum [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</a></code></pre></div>
</div>
</div>
<p><a href="code/02_Hard_Part/15_Functions.lhs" class="cut">02_Hard_Part/<strong>15_Functions.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/16_Functions.lhs" class="cut">02_Hard_Part/<strong>16_Functions.lhs</strong></a></p>
<p>Finalement</p>
<div class="sourceCode" id="cb70"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb70-1" title="1"><span class="co">-- Version 8</span></a>
<a class="sourceLine" id="cb70-2" title="2"><span class="kw">import</span> <span class="dt">Data.List</span> (foldl')</a>
<a class="sourceLine" id="cb70-3" title="3"><span class="ot">evenSum ::</span> <span class="dt">Integral</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb70-4" title="4">evenSum l <span class="ot">=</span> foldl' (<span class="op">+</span>) <span class="dv">0</span> (<span class="fu">filter</span> <span class="fu">even</span> l)</a></code></pre></div>
<p><code>foldl'</code> nest pas la fonction la plus facile à prendre en main. Si vous ny êtes pas habitué, vous devriez létudier un peu.</p>
<p>Pour mieux comprendre ce qui se passe ici, étudions une évaluation étape par étape:</p>
<pre>
<span class="yellow">evenSum [1,2,3,4]</span>
⇒ foldl' (+) 0 (<span class="yellow">filter even [1,2,3,4]</span>)
<span class="yellow">foldl' (+) 0 <span class="blue">[2,4]</span></span>
<span class="blue">foldl' (+) (<span class="yellow">0+2</span>) [4]</span>
<span class="yellow">foldl' (+) <span class="blue">2</span> [4]</span>
<span class="blue">foldl' (+) (<span class="yellow">2+4</span>) []</span>
<span class="yellow">foldl' (+) <span class="blue">6</span> []</span>
<span class="blue">6</span>
</pre>
<p>Une autre fonction dordre supérieur utile est <code>(.)</code>. Elle correspond à une composition en mathématiques.</p>
<div class="sourceCode" id="cb71"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb71-1" title="1">(f <span class="op">.</span> g <span class="op">.</span> h) x ⇔ f ( g (h x))</a></code></pre></div>
<p>Nous pouvons profiter de cet opérateur pour η-réduire notre fonction:</p>
<div class="sourceCode" id="cb72"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb72-1" title="1"><span class="co">-- Version 9</span></a>
<a class="sourceLine" id="cb72-2" title="2"><span class="kw">import</span> <span class="dt">Data.List</span> (foldl')</a>
<a class="sourceLine" id="cb72-3" title="3"><span class="ot">evenSum ::</span> <span class="dt">Integral</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb72-4" title="4">evenSum <span class="ot">=</span> (foldl' (<span class="op">+</span>) <span class="dv">0</span>) <span class="op">.</span> (<span class="fu">filter</span> <span class="fu">even</span>)</a></code></pre></div>
<p>Nous pouvons maintenant renommer certaines parties pour rendre le tout plus clair:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb73"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb73-1" title="1"><span class="co">-- Version 10</span></a>
<a class="sourceLine" id="cb73-2" title="2"><span class="kw">import</span> <span class="dt">Data.List</span> (foldl')</a>
<a class="sourceLine" id="cb73-3" title="3"><span class="ot">sum' ::</span> (<span class="dt">Num</span> a) <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb73-4" title="4">sum' <span class="ot">=</span> foldl' (<span class="op">+</span>) <span class="dv">0</span></a>
<a class="sourceLine" id="cb73-5" title="5"><span class="ot">evenSum ::</span> <span class="dt">Integral</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> a</a>
<a class="sourceLine" id="cb73-6" title="6">evenSum <span class="ot">=</span> sum' <span class="op">.</span> (<span class="fu">filter</span> <span class="fu">even</span>)</a></code></pre></div>
</div>
<p>Il est temps de discuter de la direction qua pris notre code depuis que nous avons introduit plus didiomes fonctionnels. Que gagnons-nous à utiliser des fonctions dordre supérieur?</p>
<p>Dabord, vous pourriez penser que la principale différence est la brièveté. Mais en réalité, il sagit dune meilleure façon de penser. Supposons que nous voulons modifier légèrement notre fonction, par exemple, pour quelle renvoie la somme de tous les carrés pairs des éléments de la liste.</p>
<pre><code>[1,2,3,4] ▷ [1,4,9,16] ▷ [4,16] ▷ 20</code></pre>
<p>Mettre la version 10 à jour est très facile:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb75"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb75-1" title="1">squareEvenSum <span class="ot">=</span> sum' <span class="op">.</span> (<span class="fu">filter</span> <span class="fu">even</span>) <span class="op">.</span> (<span class="fu">map</span> (<span class="op">^</span><span class="dv">2</span>))</a>
<a class="sourceLine" id="cb75-2" title="2">squareEvenSum' <span class="ot">=</span> evenSum <span class="op">.</span> (<span class="fu">map</span> (<span class="op">^</span><span class="dv">2</span>))</a></code></pre></div>
</div>
<p>Nous avons juste eu à ajouter une autre “fonction de transformation”.</p>
<pre><code>map (^2) [1,2,3,4] ⇔ [1,4,9,16]</code></pre>
<p>La fonction <code>map</code> applique simplementune fonction à tous les élements dune liste.</p>
<p>Nous navons rien modifié <em>à lintérieur</em> de notre définition de fonction. Cela rend le code plus modulaire. En plus de cela, vous pouvez penser à votre fonction plus mathématiquement. Vous pouvez aussi utilier votre fonction avec dautres, au besoin: vous pouvez utiliser <code>compose</code>, <code>map</code>, <code>fold</code> ou <code>filter</code> sur notre nouvelle fonction.</p>
<p>Modifier la version 1 est laissé comme un exercice pour le lecteur ☺.</p>
<p>Si vous croyez avoir atteint le bout de la généralisation, vous avez tout faux. Par example, il y a un moyen dutiliser cette fonction non seulement sur les listes mais aussi sur nimporte quel type récursif. Si vous voulez savoir comment, je vous suggère de lire cet article: <a href="http://eprints.eemcs.utwente.nl/7281/01/db-utwente-40501F46.pdf">Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire by Meijer, Fokkinga and Paterson</a> (<em>NDT: en anglais, mais là vous vous en seriez douté je pense ☺</em>)</p>
<p>Cet exemple montre à quel point la programmation fonctionnelle pure est géniale. Malheureusement, utiliser cet outil nest pas adapté à tous les besoins. Ou alors un langage qui le premettrait na pas encore été trouvé.</p>
<p>Une des grands pouvoirs de Haskell est sa capacité à créer des DSLs (<em>Domain Specific Language</em>, en français : <em>langage spécifique à un domaine</em>) Il est ainsi facile de changer le pardigme de programmation</p>
<p>En fait, Haskell peut très bien vous permettre décrire des programmes impératifs. Comprendre cela a été très difficile pour moi lorsque japprenais Haskell. Beaucoup defforts tendent à expliquer la supériorité de lapproche fonctionnele. Puis lorsque vous commencez à utliser le style impératif en Haskell, Il peut être difficile de comprendre quand et où lutliser.</p>
<p>Mais avant de parler de ce super-pouvoir de Haskell, nous devons parler dun autre aspet essentiel: les <em>Types</em>.</p>
<div style="display:none">
<div class="codehighlight">
<div class="sourceCode" id="cb77"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb77-1" title="1">main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> evenSum [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</a></code></pre></div>
</div>
</div>
<p><a href="code/02_Hard_Part/16_Functions.lhs" class="cut">02_Hard_Part/<strong>16_Functions.lhs</strong> </a></p>
<h3 id="types">
Les types
</h3>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/salvador-dali-the-madonna-of-port-lligat.jpg" alt="Dali, the madonna of port Lligat" />
</div>
<blockquote>
<p><span class="sc"><abbr title="Too long; didn't read">tl;dr</abbr>: </span></p>
<ul>
<li><code>type Name = AnotherType</code> nest quun alias de type, le compilateur ne fera pas la différence entre les deux.</li>
<li><code>data Name = NameConstructor AnotherType</code> le compilateur fera la différence.</li>
<li><code>data</code> permet de construire de nouvelles structures qui peuvent être récursives.</li>
<li><code>deriving</code> est magique et créé automatiquement des fonctions pour vous.</li>
</ul>
</blockquote>
<p>En Haskell, les types sont forts et statiques.</p>
<p>Pourquoi est-ce important? Cela vous aidera a éviter <em>beaucoup</em> derreurs. En Haskell, la majorité des bugs est repérée durant la compilation de votre programme. Et la raison principale de cela est linférence de type durant la compilation. Linférence de type permet de détecter plus facilement lorsque vous utilisez le mauvais paramètre au mauvais endroit, par exemple.</p>
<h4 id="type-inference">
Inférence de type
</h4>
<p>Le typage statique est généralement essentiel pour une exécution rapide. Mais la plupart des langages typés statiquement ont du mal à généraliser des concepts. La “grâce salvatrice” de Haskell est quil peut <em>inférer</em> des types.</p>
<p>Voici un exemple simple, la fonction <code>square</code> en Haskell:</p>
<div class="sourceCode" id="cb78"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb78-1" title="1">square x <span class="ot">=</span> x <span class="op">*</span> x</a></code></pre></div>
<p>Cette fonction peut mettre au carré nimporte quel type <code>Numeral</code>. Vous pouvez lutilser avec un <code>Int</code>, un <code>Integer</code>, un <code>Float</code>, un <code>Fractional</code> ou même un <code>Complex</code>. Preuve par lexemple:</p>
<pre><code>% ghci
GHCi, version 7.0.4:
...
Prelude&gt; let square x = x*x
Prelude&gt; square 2
4
Prelude&gt; square 2.1
4.41
Prelude&gt; -- charge le module Data.Complex
Prelude&gt; :m Data.Complex
Prelude Data.Complex&gt; square (2 :+ 1)
3.0 :+ 4.0</code></pre>
<p><code>x :+ y</code> est la notation pour le complexe (<i>x + iy</i>)</p>
<p>Comparons maintenant avec la quantité de code nécessaire pour le faire en C:</p>
<div class="sourceCode" id="cb80"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb80-1" title="1"><span class="dt">int</span> int_square(<span class="dt">int</span> x) { <span class="cf">return</span> x*x; }</a>
<a class="sourceLine" id="cb80-2" title="2"></a>
<a class="sourceLine" id="cb80-3" title="3"><span class="dt">float</span> float_square(<span class="dt">float</span> x) {<span class="cf">return</span> x*x; }</a>
<a class="sourceLine" id="cb80-4" title="4"></a>
<a class="sourceLine" id="cb80-5" title="5"><span class="dt">complex</span> complex_square (<span class="dt">complex</span> z) {</a>
<a class="sourceLine" id="cb80-6" title="6"> <span class="dt">complex</span> tmp;</a>
<a class="sourceLine" id="cb80-7" title="7"> tmp.real = z.real * z.real - z.img * z.img;</a>
<a class="sourceLine" id="cb80-8" title="8"> tmp.img = <span class="dv">2</span> * z.img * z.real;</a>
<a class="sourceLine" id="cb80-9" title="9">}</a>
<a class="sourceLine" id="cb80-10" title="10"></a>
<a class="sourceLine" id="cb80-11" title="11"><span class="dt">complex</span> x,y;</a>
<a class="sourceLine" id="cb80-12" title="12">y = complex_square(x);</a></code></pre></div>
<p>Pour chaque type, vous avez besoin décrire une nouvelle fonction. Le seul moyen de se débarrasser de ce problème est dutiliser des astuces de méta-programmation, par exemple en utilisant le pré-processeur. en C++ il y a un meilleur moyen, les <em>templates</em>:</p>
<pre class="{.c++}"><code>#include &lt;iostream&gt;
#include &lt;complex&gt;
using namespace std;
template&lt;typename T&gt;
T square(T x)
{
return x*x;
}
int main() {
// int
int sqr_of_five = square(5);
cout &lt;&lt; sqr_of_five &lt;&lt; endl;
// double
cout &lt;&lt; (double)square(5.3) &lt;&lt; endl;
// complex
cout &lt;&lt; square( complex&lt;double&gt;(5,3) )
&lt;&lt; endl;
return 0;
}</code></pre>
<p>C++ fait un bien meilleur travail que C ici. Mais pour des fonctions plus complexes, la syntaxe sera difficile à suivre. Voyez <a href="http://bartoszmilewski.com/2009/10/21/what-does-haskell-have-to-do-with-c/">cet article</a> pour quelques exemples. (_NDT: toujours en anglais)</p>
<p>En C++ vous devez déclarer quune fonction peut marcher avec différents types. En Haskell, cest le contraire. La fonction sera aussi générale que possible par défaut.</p>
<p>Linférence de type donne à Haskell le sentiment de liberté que les langages dynamiquement typés proposent. Mais contrairement aux langages dynamiquement typés, la majorité des erreurs est détectée avant de lancer le programme. Généralement, en Haskell:</p>
<blockquote>
<p>“Si ça compile, ça fait certainement ce que vous attendiez.”</p>
</blockquote>
<hr />
<p><a href="code/02_Hard_Part/21_Types.lhs" class="cut">02_Hard_Part/<strong>21_Types.lhs</strong></a></p>
<h4 id="type-construction">
Construction de types
</h4>
<p>Vous pouvez construire vos propres types. Dabord, vous pouvez utiliser des alias ou des synonymes de types.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb82"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb82-1" title="1"><span class="kw">type</span> <span class="dt">Name</span> <span class="ot">=</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb82-2" title="2"><span class="kw">type</span> <span class="dt">Color</span> <span class="ot">=</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb82-3" title="3"></a>
<a class="sourceLine" id="cb82-4" title="4"><span class="ot">showInfos ::</span> <span class="dt">Name</span> <span class="ot">-&gt;</span> <span class="dt">Color</span> <span class="ot">-&gt;</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb82-5" title="5">showInfos name color <span class="ot">=</span> <span class="st">&quot;Name: &quot;</span> <span class="op">++</span> name</a>
<a class="sourceLine" id="cb82-6" title="6"> <span class="op">++</span> <span class="st">&quot;, Color: &quot;</span> <span class="op">++</span> color</a>
<a class="sourceLine" id="cb82-7" title="7"><span class="ot">name ::</span> <span class="dt">Name</span></a>
<a class="sourceLine" id="cb82-8" title="8">name <span class="ot">=</span> <span class="st">&quot;Robin&quot;</span></a>
<a class="sourceLine" id="cb82-9" title="9"><span class="ot">color ::</span> <span class="dt">Color</span></a>
<a class="sourceLine" id="cb82-10" title="10">color <span class="ot">=</span> <span class="st">&quot;Blue&quot;</span></a>
<a class="sourceLine" id="cb82-11" title="11">main <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="op">$</span> showInfos name color</a></code></pre></div>
</div>
<p><a href="code/02_Hard_Part/21_Types.lhs" class="cut">02_Hard_Part/<strong>21_Types.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/22_Types.lhs" class="cut">02_Hard_Part/<strong>22_Types.lhs</strong></a></p>
<p>Mais cela ne vous protège pas tellement. Essayez dinverser les deux paramètres de <code>showInfos</code> et lancez le programme:</p>
<div class="sourceCode" id="cb83"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb83-1" title="1"> <span class="fu">putStrLn</span> <span class="op">$</span> showInfos color name</a></code></pre></div>
<p>Le code sera compilé et exécuté. En fait vous pouvez remplace Name, Color et String nimporte où. Le compilateur les traitera comme si ils était complétement identiques.</p>
<p>Une autre méthode est de créer vos propres type avec le mot-clé <code>data</code>.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb84"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb84-1" title="1"><span class="kw">data</span> <span class="dt">Name</span> <span class="ot">=</span> <span class="dt">NameConstr</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb84-2" title="2"><span class="kw">data</span> <span class="dt">Color</span> <span class="ot">=</span> <span class="dt">ColorConstr</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb84-3" title="3"></a>
<a class="sourceLine" id="cb84-4" title="4"><span class="ot">showInfos ::</span> <span class="dt">Name</span> <span class="ot">-&gt;</span> <span class="dt">Color</span> <span class="ot">-&gt;</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb84-5" title="5">showInfos (<span class="dt">NameConstr</span> name) (<span class="dt">ColorConstr</span> color) <span class="ot">=</span></a>
<a class="sourceLine" id="cb84-6" title="6"> <span class="st">&quot;Name: &quot;</span> <span class="op">++</span> name <span class="op">++</span> <span class="st">&quot;, Color: &quot;</span> <span class="op">++</span> color</a>
<a class="sourceLine" id="cb84-7" title="7"></a>
<a class="sourceLine" id="cb84-8" title="8">name <span class="ot">=</span> <span class="dt">NameConstr</span> <span class="st">&quot;Robin&quot;</span></a>
<a class="sourceLine" id="cb84-9" title="9">color <span class="ot">=</span> <span class="dt">ColorConstr</span> <span class="st">&quot;Blue&quot;</span></a>
<a class="sourceLine" id="cb84-10" title="10">main <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="op">$</span> showInfos name color</a></code></pre></div>
</div>
<p>Maintenant, si vous échangez les paramètres de <code>showInfos</code>, le compilateur se plaint! Au seul prix dêtre plus verbeux, vous écartez définitivement cette erreur potentielle.</p>
<p>Remarquez aussi que les constructeurs sont des fonctions&nbsp;:</p>
<div class="sourceCode" id="cb85"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb85-1" title="1"><span class="dt">NameConstr</span><span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Name</span></a>
<a class="sourceLine" id="cb85-2" title="2"><span class="dt">ColorConstr</span><span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Color</span></a></code></pre></div>
<p>La syntaxe de <code>data</code> est principalement:</p>
<div class="sourceCode" id="cb86"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb86-1" title="1"><span class="kw">data</span> <span class="dt">TypeName</span> <span class="ot">=</span> <span class="dt">ConstructorName</span> [types]</a>
<a class="sourceLine" id="cb86-2" title="2"> <span class="op">|</span> <span class="dt">ConstructorName2</span> [types]</a>
<a class="sourceLine" id="cb86-3" title="3"> <span class="op">|</span> <span class="op">...</span></a></code></pre></div>
<p>Généralement on utilise le même nom pour le DatatTypeName et le DataTypeConstructor.</p>
<p>Exemple&nbsp;:</p>
<div class="sourceCode" id="cb87"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb87-1" title="1"><span class="kw">data</span> <span class="dt">Complex</span> a <span class="ot">=</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> <span class="dt">Complex</span> a a</a></code></pre></div>
<p>Vous pouvez également utiliser cette syntaxe&nbsp;:</p>
<div class="sourceCode" id="cb88"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb88-1" title="1"><span class="kw">data</span> <span class="dt">DataTypeName</span> <span class="ot">=</span> <span class="dt">DataConstructor</span> {</a>
<a class="sourceLine" id="cb88-2" title="2"><span class="ot"> field1 ::</span> [<span class="kw">type</span> <span class="kw">of</span> field1]</a>
<a class="sourceLine" id="cb88-3" title="3"> ,<span class="ot"> field2 ::</span> [<span class="kw">type</span> <span class="kw">of</span> field2]</a>
<a class="sourceLine" id="cb88-4" title="4"> <span class="op">...</span></a>
<a class="sourceLine" id="cb88-5" title="5"> ,<span class="ot"> fieldn ::</span> [<span class="kw">type</span> <span class="kw">of</span> fieldn] }</a></code></pre></div>
<p>Et de nombreux accesseurs sont définis pour vous. En outre, vous pouvez utiliser une autre ordre lorsque vous définissez des valeurs.</p>
<p>Exemple&nbsp;:</p>
<div class="sourceCode" id="cb89"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb89-1" title="1"><span class="kw">data</span> <span class="dt">Complex</span> a <span class="ot">=</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> <span class="dt">Complex</span> {<span class="ot"> real ::</span> a,<span class="ot"> img ::</span> a}</a>
<a class="sourceLine" id="cb89-2" title="2">c <span class="ot">=</span> <span class="dt">Complex</span> <span class="fl">1.0</span> <span class="fl">2.0</span></a>
<a class="sourceLine" id="cb89-3" title="3">z <span class="ot">=</span> <span class="dt">Complex</span> { real <span class="ot">=</span> <span class="dv">3</span>, img <span class="ot">=</span> <span class="dv">4</span> }</a>
<a class="sourceLine" id="cb89-4" title="4">real c <span class="ot"></span> <span class="fl">1.0</span></a>
<a class="sourceLine" id="cb89-5" title="5">img z <span class="ot"></span> <span class="dv">4</span></a></code></pre></div>
<p><a href="code/02_Hard_Part/22_Types.lhs" class="cut">02_Hard_Part/<strong>22_Types.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/23_Types.lhs" class="cut">02_Hard_Part/<strong>23_Types.lhs</strong></a></p>
<h4 id="recursive-type">
Type récursif
</h4>
<p>Nous avons déjà rencontré un type récursif : les listes. Nous pourrions re-créer les listes, avec une syntaxe plus bavarde:</p>
<div class="sourceCode" id="cb90"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb90-1" title="1"><span class="kw">data</span> <span class="dt">List</span> a <span class="ot">=</span> <span class="dt">Empty</span> <span class="op">|</span> <span class="dt">Cons</span> a (<span class="dt">List</span> a)</a></code></pre></div>
<p>Si vous voulez réellement utiliser une syntxe plus simple, utilisez un nom infixe pour les constructeurs.</p>
<div class="sourceCode" id="cb91"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb91-1" title="1"><span class="kw">infixr</span> <span class="dv">5</span> <span class="op">:::</span></a>
<a class="sourceLine" id="cb91-2" title="2"><span class="kw">data</span> <span class="dt">List</span> a <span class="ot">=</span> <span class="dt">Nil</span> <span class="op">|</span> a <span class="op">:::</span> (<span class="dt">List</span> a)</a></code></pre></div>
<p>Le nombre après <code>infixr</code> donne la priorité.</p>
<p>Si vous voulez pouvoir écrire (<code>Show</code>), lire (<code>Read</code>), tester légalité (<code>Eq</code>) et comparer (<code>Ord</code>) votre nouvelle structure, vous pouvez demander à Haskell de dériver les fonctions appropriées pour vous.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb92"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb92-1" title="1"><span class="kw">infixr</span> <span class="dv">5</span> <span class="op">:::</span></a>
<a class="sourceLine" id="cb92-2" title="2"><span class="kw">data</span> <span class="dt">List</span> a <span class="ot">=</span> <span class="dt">Nil</span> <span class="op">|</span> a <span class="op">:::</span> (<span class="dt">List</span> a)</a>
<a class="sourceLine" id="cb92-3" title="3"> <span class="kw">deriving</span> (<span class="dt">Show</span>,<span class="dt">Read</span>,<span class="dt">Eq</span>,<span class="dt">Ord</span>)</a></code></pre></div>
</div>
<p>Quand vous ajoutez <code>deriving (Show)</code> à votre déclaration, Haskell crée une fonction <code>show</code> pour vous. Nous verrons bientôt comment utiliser sa propre fonction <code>show</code>.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb93"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb93-1" title="1">convertList [] <span class="ot">=</span> <span class="dt">Nil</span></a>
<a class="sourceLine" id="cb93-2" title="2">convertList (x<span class="op">:</span>xs) <span class="ot">=</span> x <span class="op">:::</span> convertList xs</a></code></pre></div>
</div>
<div class="codehighlight">
<div class="sourceCode" id="cb94"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb94-1" title="1">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb94-2" title="2"> <span class="fu">print</span> (<span class="dv">0</span> <span class="op">:::</span> <span class="dv">1</span> <span class="op">:::</span> <span class="dt">Nil</span>)</a>
<a class="sourceLine" id="cb94-3" title="3"> <span class="fu">print</span> (convertList [<span class="dv">0</span>,<span class="dv">1</span>])</a></code></pre></div>
</div>
<p>Ceci donne&nbsp;:</p>
<pre><code>0 ::: (1 ::: Nil)
0 ::: (1 ::: Nil)</code></pre>
<p><a href="code/02_Hard_Part/23_Types.lhs" class="cut">02_Hard_Part/<strong>23_Types.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/30_Trees.lhs" class="cut">02_Hard_Part/<strong>30_Trees.lhs</strong></a></p>
<h4 id="trees">
Les arbres
</h4>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/magritte-l-arbre.jpg" alt="Magritte, l" />
</div>
<p>Voici une autre exemple standard : les arbres binaires.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb96"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb96-1" title="1"><span class="kw">import</span> <span class="dt">Data.List</span></a>
<a class="sourceLine" id="cb96-2" title="2"></a>
<a class="sourceLine" id="cb96-3" title="3"><span class="kw">data</span> <span class="dt">BinTree</span> a <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb96-4" title="4"> <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">BinTree</span> a) (<span class="dt">BinTree</span> a)</a>
<a class="sourceLine" id="cb96-5" title="5"> <span class="kw">deriving</span> (<span class="dt">Show</span>)</a></code></pre></div>
</div>
<p>Créons aussi une fonctions qui transforme une liste en un arbre binaire ordonné.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb97"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb97-1" title="1"><span class="ot">treeFromList ::</span> (<span class="dt">Ord</span> a) <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">BinTree</span> a</a>
<a class="sourceLine" id="cb97-2" title="2">treeFromList [] <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb97-3" title="3">treeFromList (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Node</span> x (treeFromList (<span class="fu">filter</span> (<span class="op">&lt;</span>x) xs))</a>
<a class="sourceLine" id="cb97-4" title="4"> (treeFromList (<span class="fu">filter</span> (<span class="op">&gt;</span>x) xs))</a></code></pre></div>
</div>
<p>Remarquez à quel point cette fonction est élégante. En français&nbsp;:</p>
<ul>
<li>une liste vide est convertie en un arbre vide</li>
<li>une liste <code>(x:xs)</code> sera convertie en un arbre où :
<ul>
<li>La racine est <code>x</code></li>
<li>Le “sous-arbre” de gauche est larbre créé à partir des membres de la liste <code>xs</code> strictement inférieurs à <code>x</code></li>
<li>Le “sous-arbre” de droite est larbre créé à partir des membres de la liste <code>xs</code> strictement superieurs à <code>x</code></li>
</ul></li>
</ul>
<div class="codehighlight">
<div class="sourceCode" id="cb98"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb98-1" title="1">main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> treeFromList [<span class="dv">7</span>,<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">8</span>]</a></code></pre></div>
</div>
<p>Vous devriez obtenir&nbsp;:</p>
<pre><code>Node 7 (Node 2 Empty (Node 4 Empty Empty)) (Node 8 Empty Empty)</code></pre>
<p>Cest une représentation de notre arbre informative mais plutôt déplaisante.</p>
<p><a href="code/02_Hard_Part/30_Trees.lhs" class="cut">02_Hard_Part/<strong>30_Trees.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/31_Trees.lhs" class="cut">02_Hard_Part/<strong>31_Trees.lhs</strong></a></p>
<p>Juste pour le plaisir, codons un meilleur affichage pour nos arbres. Je me suis simplement amusé à faire une belle fonction pour afficher les arbres de façon générale. Vous pouvez passer cette partie si vous la trouvez difficile à suivre.</p>
<p>Nous avons quelques changements à faire. Enlevons le <code>deriving (Show)</code> de la déclaration de notre type <code>BinTree</code>. Il serait aussi utile de faire de BinTree une instance de (<code>Eq</code> et <code>Ord</code>), nous serons ainsi capable de tester légalité et de comparer des arbres.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb100"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb100-1" title="1"><span class="kw">data</span> <span class="dt">BinTree</span> a <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb100-2" title="2"> <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">BinTree</span> a) (<span class="dt">BinTree</span> a)</a>
<a class="sourceLine" id="cb100-3" title="3"> <span class="kw">deriving</span> (<span class="dt">Eq</span>,<span class="dt">Ord</span>)</a></code></pre></div>
</div>
<p>Sans le <code>deriving (Show)</code>, Haskell ne crée pas de méthode <code>show</code> pour nous. Nous allons créer notre propre version. Pour accomplir cela, nous devons déclarer que notre type <code>BinTree a</code> est une instance de la classe de type <code>Show</code>. La syntaxe générale est&nbsp;:</p>
<div class="sourceCode" id="cb101"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb101-1" title="1"><span class="kw">instance</span> <span class="dt">Show</span> (<span class="dt">BinTree</span> a) <span class="kw">where</span></a>
<a class="sourceLine" id="cb101-2" title="2"> <span class="fu">show</span> t <span class="ot">=</span> <span class="op">...</span> <span class="co">-- Déclarez votre fonction ici</span></a></code></pre></div>
<p>Voici ma version pour afficher un arbre binaire. Ne vous inquiétez pas de sa complexité apparente. Jai fait beaucoup daméliorations pour afficher même les objets les plus étranges.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb102"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb102-1" title="1"><span class="co">-- declare BinTree a to be an instance of Show</span></a>
<a class="sourceLine" id="cb102-2" title="2"><span class="kw">instance</span> (<span class="dt">Show</span> a) <span class="ot">=&gt;</span> <span class="dt">Show</span> (<span class="dt">BinTree</span> a) <span class="kw">where</span></a>
<a class="sourceLine" id="cb102-3" title="3"> <span class="co">-- will start by a '&lt;' before the root</span></a>
<a class="sourceLine" id="cb102-4" title="4"> <span class="co">-- and put a : a begining of line</span></a>
<a class="sourceLine" id="cb102-5" title="5"> <span class="fu">show</span> t <span class="ot">=</span> <span class="st">&quot;&lt; &quot;</span> <span class="op">++</span> replace <span class="ch">'\n'</span> <span class="st">&quot;\n: &quot;</span> (treeshow <span class="st">&quot;&quot;</span> t)</a>
<a class="sourceLine" id="cb102-6" title="6"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb102-7" title="7"> <span class="co">-- treeshow pref Tree</span></a>
<a class="sourceLine" id="cb102-8" title="8"> <span class="co">-- shows a tree and starts each line with pref</span></a>
<a class="sourceLine" id="cb102-9" title="9"> <span class="co">-- We don't display the Empty tree</span></a>
<a class="sourceLine" id="cb102-10" title="10"> treeshow pref <span class="dt">Empty</span> <span class="ot">=</span> <span class="st">&quot;&quot;</span></a>
<a class="sourceLine" id="cb102-11" title="11"> <span class="co">-- Leaf</span></a>
<a class="sourceLine" id="cb102-12" title="12"> treeshow pref (<span class="dt">Node</span> x <span class="dt">Empty</span> <span class="dt">Empty</span>) <span class="ot">=</span></a>
<a class="sourceLine" id="cb102-13" title="13"> (pshow pref x)</a>
<a class="sourceLine" id="cb102-14" title="14"></a>
<a class="sourceLine" id="cb102-15" title="15"> <span class="co">-- Right branch is empty</span></a>
<a class="sourceLine" id="cb102-16" title="16"> treeshow pref (<span class="dt">Node</span> x left <span class="dt">Empty</span>) <span class="ot">=</span></a>
<a class="sourceLine" id="cb102-17" title="17"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb102-18" title="18"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> left)</a>
<a class="sourceLine" id="cb102-19" title="19"></a>
<a class="sourceLine" id="cb102-20" title="20"> <span class="co">-- Left branch is empty</span></a>
<a class="sourceLine" id="cb102-21" title="21"> treeshow pref (<span class="dt">Node</span> x <span class="dt">Empty</span> right) <span class="ot">=</span></a>
<a class="sourceLine" id="cb102-22" title="22"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb102-23" title="23"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> right)</a>
<a class="sourceLine" id="cb102-24" title="24"></a>
<a class="sourceLine" id="cb102-25" title="25"> <span class="co">-- Tree with left and right children non empty</span></a>
<a class="sourceLine" id="cb102-26" title="26"> treeshow pref (<span class="dt">Node</span> x left right) <span class="ot">=</span></a>
<a class="sourceLine" id="cb102-27" title="27"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb102-28" title="28"> (showSon pref <span class="st">&quot;|--&quot;</span> <span class="st">&quot;| &quot;</span> left) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb102-29" title="29"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> right)</a>
<a class="sourceLine" id="cb102-30" title="30"></a>
<a class="sourceLine" id="cb102-31" title="31"> <span class="co">-- shows a tree using some prefixes to make it nice</span></a>
<a class="sourceLine" id="cb102-32" title="32"> showSon pref before next t <span class="ot">=</span></a>
<a class="sourceLine" id="cb102-33" title="33"> pref <span class="op">++</span> before <span class="op">++</span> treeshow (pref <span class="op">++</span> next) t</a>
<a class="sourceLine" id="cb102-34" title="34"></a>
<a class="sourceLine" id="cb102-35" title="35"> <span class="co">-- pshow replaces &quot;\n&quot; by &quot;\n&quot;++pref</span></a>
<a class="sourceLine" id="cb102-36" title="36"> pshow pref x <span class="ot">=</span> replace <span class="ch">'\n'</span> (<span class="st">&quot;\n&quot;</span><span class="op">++</span>pref) (<span class="fu">show</span> x)</a>
<a class="sourceLine" id="cb102-37" title="37"></a>
<a class="sourceLine" id="cb102-38" title="38"> <span class="co">-- replaces one char by another string</span></a>
<a class="sourceLine" id="cb102-39" title="39"> replace c new string <span class="ot">=</span></a>
<a class="sourceLine" id="cb102-40" title="40"> <span class="fu">concatMap</span> (change c new) string</a>
<a class="sourceLine" id="cb102-41" title="41"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb102-42" title="42"> change c new x</a>
<a class="sourceLine" id="cb102-43" title="43"> <span class="op">|</span> x <span class="op">==</span> c <span class="ot">=</span> new</a>
<a class="sourceLine" id="cb102-44" title="44"> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> x<span class="op">:</span>[] <span class="co">-- &quot;x&quot;</span></a></code></pre></div>
</div>
<p>La méthode <code>treeFromList</code> reste identique.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb103"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb103-1" title="1"><span class="ot">treeFromList ::</span> (<span class="dt">Ord</span> a) <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">BinTree</span> a</a>
<a class="sourceLine" id="cb103-2" title="2">treeFromList [] <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb103-3" title="3">treeFromList (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Node</span> x (treeFromList (<span class="fu">filter</span> (<span class="op">&lt;</span>x) xs))</a>
<a class="sourceLine" id="cb103-4" title="4"> (treeFromList (<span class="fu">filter</span> (<span class="op">&gt;</span>x) xs))</a></code></pre></div>
</div>
<p>Et maintenant, nous pouvons jouer&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb104"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb104-1" title="1">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb104-2" title="2"> <span class="fu">putStrLn</span> <span class="st">&quot;Int binary tree:&quot;</span></a>
<a class="sourceLine" id="cb104-3" title="3"> <span class="fu">print</span> <span class="op">$</span> treeFromList [<span class="dv">7</span>,<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">8</span>,<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">6</span>,<span class="dv">21</span>,<span class="dv">12</span>,<span class="dv">23</span>]</a></code></pre></div>
</div>
<pre><code>Arbre binaire d'Int:
&lt; 7
: |--2
: | |--1
: | `--4
: | |--3
: | `--6
: `--8
: `--21
: |--12
: `--23</code></pre>
<p>Maintenant cest beaucoup mieux ! La racine est montrée en commençant la ligne avec le caractère <code>&lt;</code>. Et chaque ligne suivante est commence par <code>:</code>. Mais nous pourrions aussi utiliser un autre type.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb106"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb106-1" title="1"> <span class="fu">putStrLn</span> <span class="st">&quot;\nString binary tree:&quot;</span></a>
<a class="sourceLine" id="cb106-2" title="2"> <span class="fu">print</span> <span class="op">$</span> treeFromList [<span class="st">&quot;foo&quot;</span>,<span class="st">&quot;bar&quot;</span>,<span class="st">&quot;baz&quot;</span>,<span class="st">&quot;gor&quot;</span>,<span class="st">&quot;yog&quot;</span>]</a></code></pre></div>
</div>
<pre><code>Arbre binaire de chaînes de caractères
&lt; &quot;foo&quot;
: |--&quot;bar&quot;
: | `--&quot;baz&quot;
: `--&quot;gor&quot;
: `--&quot;yog&quot;</code></pre>
<p>Commme nous pouvons tester légalité et ordonner des arbres, nous pouvons aussi faire des arbres darbres!</p>
<div class="codehighlight">
<div class="sourceCode" id="cb108"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb108-1" title="1"> <span class="fu">putStrLn</span> <span class="st">&quot;\nBinary tree of Char binary trees:&quot;</span></a>
<a class="sourceLine" id="cb108-2" title="2"> <span class="fu">print</span> ( treeFromList</a>
<a class="sourceLine" id="cb108-3" title="3"> (<span class="fu">map</span> treeFromList [<span class="st">&quot;baz&quot;</span>,<span class="st">&quot;zara&quot;</span>,<span class="st">&quot;bar&quot;</span>]))</a></code></pre></div>
</div>
<pre><code>Arbre binaire d'arbres binaires de Char :
&lt; &lt; 'b'
: : |--'a'
: : `--'z'
: |--&lt; 'b'
: | : |--'a'
: | : `--'r'
: `--&lt; 'z'
: : `--'a'
: : `--'r'</code></pre>
<p>Cest pour cela que jai choisi de préfixer chaque ligne par un <code>:</code> (sauf pour la racine).</p>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/yo_dawg_tree.jpg" alt="Yo Dawg Tree" />
</div>
<div class="codehighlight">
<div class="sourceCode" id="cb110"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb110-1" title="1"> <span class="fu">putStrLn</span> <span class="st">&quot;\nTree of Binary trees of Char binary trees:&quot;</span></a>
<a class="sourceLine" id="cb110-2" title="2"> <span class="fu">print</span> <span class="op">$</span> (treeFromList <span class="op">.</span> <span class="fu">map</span> (treeFromList <span class="op">.</span> <span class="fu">map</span> treeFromList))</a>
<a class="sourceLine" id="cb110-3" title="3"> [ [<span class="st">&quot;YO&quot;</span>,<span class="st">&quot;DAWG&quot;</span>]</a>
<a class="sourceLine" id="cb110-4" title="4"> , [<span class="st">&quot;I&quot;</span>,<span class="st">&quot;HEARD&quot;</span>]</a>
<a class="sourceLine" id="cb110-5" title="5"> , [<span class="st">&quot;I&quot;</span>,<span class="st">&quot;HEARD&quot;</span>]</a>
<a class="sourceLine" id="cb110-6" title="6"> , [<span class="st">&quot;YOU&quot;</span>,<span class="st">&quot;LIKE&quot;</span>,<span class="st">&quot;TREES&quot;</span>] ]</a></code></pre></div>
</div>
<p>Qui est équivalent à</p>
<div class="sourceCode" id="cb111"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb111-1" title="1"><span class="fu">print</span> ( treeFromList (</a>
<a class="sourceLine" id="cb111-2" title="2"> <span class="fu">map</span> treeFromList</a>
<a class="sourceLine" id="cb111-3" title="3"> [ <span class="fu">map</span> treeFromList [<span class="st">&quot;YO&quot;</span>,<span class="st">&quot;DAWG&quot;</span>]</a>
<a class="sourceLine" id="cb111-4" title="4"> , <span class="fu">map</span> treeFromList [<span class="st">&quot;I&quot;</span>,<span class="st">&quot;HEARD&quot;</span>]</a>
<a class="sourceLine" id="cb111-5" title="5"> , <span class="fu">map</span> treeFromList [<span class="st">&quot;I&quot;</span>,<span class="st">&quot;HEARD&quot;</span>]</a>
<a class="sourceLine" id="cb111-6" title="6"> , <span class="fu">map</span> treeFromList [<span class="st">&quot;YOU&quot;</span>,<span class="st">&quot;LIKE&quot;</span>,<span class="st">&quot;TREES&quot;</span>] ]))</a></code></pre></div>
<p>et donne&nbsp;:</p>
<pre><code>Arbre d'arbres d'arbres de Char :
&lt; &lt; &lt; 'Y'
: : : `--'O'
: : `--&lt; 'D'
: : : |--'A'
: : : `--'W'
: : : `--'G'
: |--&lt; &lt; 'I'
: | : `--&lt; 'H'
: | : : |--'E'
: | : : | `--'A'
: | : : | `--'D'
: | : : `--'R'
: `--&lt; &lt; 'Y'
: : : `--'O'
: : : `--'U'
: : `--&lt; 'L'
: : : `--'I'
: : : |--'E'
: : : `--'K'
: : `--&lt; 'T'
: : : `--'R'
: : : |--'E'
: : : `--'S'</code></pre>
<p>Remarquez que les arbres en double ne sont pas insérés. Il ny a quun seul arbre correspondant à <code>"I","HEARD"</code>. Nous avons ceci presque gratuitement, car nous avons déclaré Tree comme instance de <code>Eq</code>.</p>
<p>Voyez à quel point cette structure est formidable : Nous pouvons faire des arbres contenant seulement des entiers, des chaînes de caractères, mais aussi dautres arbres. Et nous pouvons même faire un arbre contenant un arbre darbres!</p>
<p><a href="code/02_Hard_Part/31_Trees.lhs" class="cut">02_Hard_Part/<strong>31_Trees.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/40_Infinites_Structures.lhs" class="cut">02_Hard_Part/<strong>40_Infinites_Structures.lhs</strong></a></p>
<h3 id="infinite-structures">
Structures infinies
</h3>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/escher_infinite_lizards.jpg" alt="Escher" />
</div>
<p>On dit souvent que Haskell est <em>paresseux</em>.</p>
<p>En fait, si vous êtes un petit peu pédant, vous devriez dire que <a href="http://www.haskell.org/haskellwiki/Lazy_vs._non-strict">Haskell est <em>non-strict</em></a> (<em>NDT: En anglais, pour changer</em>). La paresse est juste une implémentation commune aux langages non-stricts.</p>
<p>Alors que signifie “non-strict”? Daprès le wiki de Haskell&nbsp;:</p>
<blockquote>
<p>La réduction (terme mathématique pour “évaluation”) procède depuis lextérieur.</p>
<p>Donc si vous avez <code>(a+(b*c))</code>, alors vous réduisez <code>+</code> dabord, puis vous réduisez <code>(b*c)</code></p>
</blockquote>
<p>Par exemple en Haskell vous pouvez faire&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb113"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb113-1" title="1"><span class="co">-- numbers = [1,2,..]</span></a>
<a class="sourceLine" id="cb113-2" title="2"><span class="ot">numbers ::</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb113-3" title="3">numbers <span class="ot">=</span> <span class="dv">0</span><span class="op">:</span><span class="fu">map</span> (<span class="dv">1</span><span class="op">+</span>) numbers</a>
<a class="sourceLine" id="cb113-4" title="4"></a>
<a class="sourceLine" id="cb113-5" title="5">take' n [] <span class="ot">=</span> []</a>
<a class="sourceLine" id="cb113-6" title="6">take' <span class="dv">0</span> l <span class="ot">=</span> []</a>
<a class="sourceLine" id="cb113-7" title="7">take' n (x<span class="op">:</span>xs) <span class="ot">=</span> x<span class="op">:</span>take' (n<span class="op">-</span><span class="dv">1</span>) xs</a>
<a class="sourceLine" id="cb113-8" title="8"></a>
<a class="sourceLine" id="cb113-9" title="9">main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> take' <span class="dv">10</span> numbers</a></code></pre></div>
</div>
<p>Et ça sarrête.</p>
<p>Comment ?</p>
<p>Au lieu dessayer dévaluer <code>numbers</code> entièrement, Haskell évalue les éléments seulement lorsque cest nécessaire.</p>
<p>Remarquez aussi quen Haskell, il y a une notation pour les listes infinies</p>
<pre><code>[1..] ⇔ [1,2,3,4...]
[1,3..] ⇔ [1,3,5,7,9,11...]</code></pre>
<p>et que la majorité des fonctions fonctionnera avec ces listes. Il y a aussi une fonction <code>take</code> équivalente à notre <code>take'</code>.</p>
<p><a href="code/02_Hard_Part/40_Infinites_Structures.lhs" class="cut">02_Hard_Part/<strong>40_Infinites_Structures.lhs</strong> </a></p>
<hr />
<p><a href="code/02_Hard_Part/41_Infinites_Structures.lhs" class="cut">02_Hard_Part/<strong>41_Infinites_Structures.lhs</strong></a></p>
<div style="display:none">
<p>This code is mostly the same as the previous one.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb115"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb115-1" title="1"><span class="kw">import</span> <span class="dt">Debug.Trace</span> (trace)</a>
<a class="sourceLine" id="cb115-2" title="2"><span class="kw">import</span> <span class="dt">Data.List</span></a>
<a class="sourceLine" id="cb115-3" title="3"><span class="kw">data</span> <span class="dt">BinTree</span> a <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb115-4" title="4"> <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">BinTree</span> a) (<span class="dt">BinTree</span> a)</a>
<a class="sourceLine" id="cb115-5" title="5"> <span class="kw">deriving</span> (<span class="dt">Eq</span>,<span class="dt">Ord</span>)</a></code></pre></div>
</div>
<div class="codehighlight">
<div class="sourceCode" id="cb116"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb116-1" title="1"><span class="co">-- declare BinTree a to be an instance of Show</span></a>
<a class="sourceLine" id="cb116-2" title="2"><span class="kw">instance</span> (<span class="dt">Show</span> a) <span class="ot">=&gt;</span> <span class="dt">Show</span> (<span class="dt">BinTree</span> a) <span class="kw">where</span></a>
<a class="sourceLine" id="cb116-3" title="3"> <span class="co">-- will start by a '&lt;' before the root</span></a>
<a class="sourceLine" id="cb116-4" title="4"> <span class="co">-- and put a : a begining of line</span></a>
<a class="sourceLine" id="cb116-5" title="5"> <span class="fu">show</span> t <span class="ot">=</span> <span class="st">&quot;&lt; &quot;</span> <span class="op">++</span> replace <span class="ch">'\n'</span> <span class="st">&quot;\n: &quot;</span> (treeshow <span class="st">&quot;&quot;</span> t)</a>
<a class="sourceLine" id="cb116-6" title="6"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb116-7" title="7"> treeshow pref <span class="dt">Empty</span> <span class="ot">=</span> <span class="st">&quot;&quot;</span></a>
<a class="sourceLine" id="cb116-8" title="8"> treeshow pref (<span class="dt">Node</span> x <span class="dt">Empty</span> <span class="dt">Empty</span>) <span class="ot">=</span></a>
<a class="sourceLine" id="cb116-9" title="9"> (pshow pref x)</a>
<a class="sourceLine" id="cb116-10" title="10"></a>
<a class="sourceLine" id="cb116-11" title="11"> treeshow pref (<span class="dt">Node</span> x left <span class="dt">Empty</span>) <span class="ot">=</span></a>
<a class="sourceLine" id="cb116-12" title="12"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb116-13" title="13"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> left)</a>
<a class="sourceLine" id="cb116-14" title="14"></a>
<a class="sourceLine" id="cb116-15" title="15"> treeshow pref (<span class="dt">Node</span> x <span class="dt">Empty</span> right) <span class="ot">=</span></a>
<a class="sourceLine" id="cb116-16" title="16"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb116-17" title="17"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> right)</a>
<a class="sourceLine" id="cb116-18" title="18"></a>
<a class="sourceLine" id="cb116-19" title="19"> treeshow pref (<span class="dt">Node</span> x left right) <span class="ot">=</span></a>
<a class="sourceLine" id="cb116-20" title="20"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb116-21" title="21"> (showSon pref <span class="st">&quot;|--&quot;</span> <span class="st">&quot;| &quot;</span> left) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb116-22" title="22"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> right)</a>
<a class="sourceLine" id="cb116-23" title="23"></a>
<a class="sourceLine" id="cb116-24" title="24"> <span class="co">-- show a tree using some prefixes to make it nice</span></a>
<a class="sourceLine" id="cb116-25" title="25"> showSon pref before next t <span class="ot">=</span></a>
<a class="sourceLine" id="cb116-26" title="26"> pref <span class="op">++</span> before <span class="op">++</span> treeshow (pref <span class="op">++</span> next) t</a>
<a class="sourceLine" id="cb116-27" title="27"></a>
<a class="sourceLine" id="cb116-28" title="28"> <span class="co">-- pshow replace &quot;\n&quot; by &quot;\n&quot;++pref</span></a>
<a class="sourceLine" id="cb116-29" title="29"> pshow pref x <span class="ot">=</span> replace <span class="ch">'\n'</span> (<span class="st">&quot;\n&quot;</span><span class="op">++</span>pref) (<span class="st">&quot; &quot;</span> <span class="op">++</span> <span class="fu">show</span> x)</a>
<a class="sourceLine" id="cb116-30" title="30"></a>
<a class="sourceLine" id="cb116-31" title="31"> <span class="co">-- replace on char by another string</span></a>
<a class="sourceLine" id="cb116-32" title="32"> replace c new string <span class="ot">=</span></a>
<a class="sourceLine" id="cb116-33" title="33"> <span class="fu">concatMap</span> (change c new) string</a>
<a class="sourceLine" id="cb116-34" title="34"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb116-35" title="35"> change c new x</a>
<a class="sourceLine" id="cb116-36" title="36"> <span class="op">|</span> x <span class="op">==</span> c <span class="ot">=</span> new</a>
<a class="sourceLine" id="cb116-37" title="37"> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> x<span class="op">:</span>[] <span class="co">-- &quot;x&quot;</span></a></code></pre></div>
</div>
</div>
<p>Supposons que nous ne nous préoccupions pas davoir une arbre ordonné. Voici un arbre binaire infini&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb117"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb117-1" title="1">nullTree <span class="ot">=</span> <span class="dt">Node</span> <span class="dv">0</span> nullTree nullTree</a></code></pre></div>
</div>
<p>Un arbre complet où chaque noeud est égal à 0. Maintenant je vais vous prouver que nous pouvons manipuler cet arbre avec la fonction suivante&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb118"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb118-1" title="1"><span class="co">-- take all element of a BinTree</span></a>
<a class="sourceLine" id="cb118-2" title="2"><span class="co">-- up to some depth</span></a>
<a class="sourceLine" id="cb118-3" title="3">treeTakeDepth _ <span class="dt">Empty</span> <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb118-4" title="4">treeTakeDepth <span class="dv">0</span> _ <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb118-5" title="5">treeTakeDepth n (<span class="dt">Node</span> x left right) <span class="ot">=</span> <span class="kw">let</span></a>
<a class="sourceLine" id="cb118-6" title="6"> nl <span class="ot">=</span> treeTakeDepth (n<span class="op">-</span><span class="dv">1</span>) left</a>
<a class="sourceLine" id="cb118-7" title="7"> nr <span class="ot">=</span> treeTakeDepth (n<span class="op">-</span><span class="dv">1</span>) right</a>
<a class="sourceLine" id="cb118-8" title="8"> <span class="kw">in</span></a>
<a class="sourceLine" id="cb118-9" title="9"> <span class="dt">Node</span> x nl nr</a></code></pre></div>
</div>
<p>Regardez ce qui se passe avec ce programme&nbsp;:</p>
<div class="sourceCode" id="cb119"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb119-1" title="1">main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> treeTakeDepth <span class="dv">4</span> nullTree</a></code></pre></div>
<p>Le code compile, se lance et sarrête en donnant ce résultat&nbsp;:</p>
<pre><code>&lt; 0
: |-- 0
: | |-- 0
: | | |-- 0
: | | `-- 0
: | `-- 0
: | |-- 0
: | `-- 0
: `-- 0
: |-- 0
: | |-- 0
: | `-- 0
: `-- 0
: |-- 0
: `-- 0</code></pre>
<p>Pour nous chauffer encore un peu les neurones, faisons un arbre plus intéressant&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb121"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb121-1" title="1">iTree <span class="ot">=</span> <span class="dt">Node</span> <span class="dv">0</span> (dec iTree) (inc iTree)</a>
<a class="sourceLine" id="cb121-2" title="2"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb121-3" title="3"> dec (<span class="dt">Node</span> x l r) <span class="ot">=</span> <span class="dt">Node</span> (x<span class="op">-</span><span class="dv">1</span>) (dec l) (dec r)</a>
<a class="sourceLine" id="cb121-4" title="4"> inc (<span class="dt">Node</span> x l r) <span class="ot">=</span> <span class="dt">Node</span> (x<span class="op">+</span><span class="dv">1</span>) (inc l) (inc r)</a></code></pre></div>
</div>
<p>Un autre moyen de créer cet arbre est dutiliser une fonction dordre supérieur. Cette fonction devrait être similaire à <code>map</code> n, mais devrait travailler sur un <code>BinTree</code> au lieu dune liste. Voici cette fonction&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb122"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb122-1" title="1"><span class="co">-- apply a function to each node of Tree</span></a>
<a class="sourceLine" id="cb122-2" title="2"><span class="ot">treeMap ::</span> (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> <span class="dt">BinTree</span> a <span class="ot">-&gt;</span> <span class="dt">BinTree</span> b</a>
<a class="sourceLine" id="cb122-3" title="3">treeMap f <span class="dt">Empty</span> <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb122-4" title="4">treeMap f (<span class="dt">Node</span> x left right) <span class="ot">=</span> <span class="dt">Node</span> (f x)</a>
<a class="sourceLine" id="cb122-5" title="5"> (treeMap f left)</a>
<a class="sourceLine" id="cb122-6" title="6"> (treeMap f right)</a></code></pre></div>
</div>
<p><em>NB</em>: Je ne parlerai pas plus de cette fonction ici. Si vous vous intéressez à la généralisation de <code>map</code> à dautres structures de données, cherchez des informations sur les foncteurs et <code>fmap</code>.</p>
<p>Notre définition est maintenant&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb123"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb123-1" title="1"><span class="ot">infTreeTwo ::</span> <span class="dt">BinTree</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb123-2" title="2">infTreeTwo <span class="ot">=</span> <span class="dt">Node</span> <span class="dv">0</span> (treeMap (\x <span class="ot">-&gt;</span> x<span class="op">-</span><span class="dv">1</span>) infTreeTwo)</a>
<a class="sourceLine" id="cb123-3" title="3"> (treeMap (\x <span class="ot">-&gt;</span> x<span class="op">+</span><span class="dv">1</span>) infTreeTwo)</a></code></pre></div>
</div>
<p>Regardez le résultat pour</p>
<div class="sourceCode" id="cb124"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb124-1" title="1">main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> treeTakeDepth <span class="dv">4</span> infTreeTwo</a></code></pre></div>
<pre><code>&lt; 0
: |-- -1
: | |-- -2
: | | |-- -3
: | | `-- -1
: | `-- 0
: | |-- -1
: | `-- 1
: `-- 1
: |-- 0
: | |-- -1
: | `-- 1
: `-- 2
: |-- 1
: `-- 3</code></pre>
<div style="display:none">
<div class="codehighlight">
<div class="sourceCode" id="cb126"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb126-1" title="1">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb126-2" title="2"> <span class="fu">print</span> <span class="op">$</span> treeTakeDepth <span class="dv">4</span> nullTree</a>
<a class="sourceLine" id="cb126-3" title="3"> <span class="fu">print</span> <span class="op">$</span> treeTakeDepth <span class="dv">4</span> infTreeTwo</a></code></pre></div>
</div>
</div>
<p><a href="code/02_Hard_Part/41_Infinites_Structures.lhs" class="cut">02_Hard_Part/<strong>41_Infinites_Structures.lhs</strong> </a></p>
<h2 id="hell-difficulty-part">
Partie de difficulté infernale
</h2>
<p>Félicitations pour être allé si loin! Maitenant, les choses vraiment extrêmes peuvent commencer.</p>
<p>Si vous êtes comme moi, vous êtes déjà familier avec le style fonctionnel. Vous devriez également comprendre les avantages de la paresse par défaut. Mais vous ne comprenez peut-être pas vraiment par où commencer pour faire un vrai programme. Et en particulier&nbsp;:</p>
<ul>
<li>Comment soccuper des effets ?</li>
<li>Pourquoi y a t-il une étrange notation impérative lorsque lon soccupe de lEntrée/Sortie? (E/S, <em>IO</em> pour <em>Input/Output</em> en anglais)</li>
</ul>
<p>Accrochez-vous, les réponses risquent dêtre compliquées. Mais elles en valent la peine.</p>
<hr />
<p><a href="code/03_Hell/01_IO/01_progressive_io_example.lhs" class="cut">03_Hell/01_IO/<strong>01_progressive_io_example.lhs</strong></a></p>
<h3 id="deal-with-io">
Soccuper de lE/S (IO)
</h3>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/magritte_carte_blanche.jpg" alt="Magritte, Carte blanche" />
</div>
<blockquote>
<p><span class="sc"><abbr title="Too long; didn't read">tl;dr</abbr>: </span></p>
<p>Une fonction typique qui fait de l<code>IO</code> ressemble à un programme impératif:</p>
<pre><code>f :: IO a
f = do
x &lt;- action1
action2 x
y &lt;- action3
action4 x y</code></pre>
<ul>
<li>Pour définir la valeur dun objet on utilise <code>&lt;-</code> .</li>
<li>Le type de chaque ligne est <code>IO *</code>; dans cet exemple:
<ul>
<li><code>action1 :: IO b</code></li>
<li><code>action2 x :: IO ()</code></li>
<li><code>action3 :: IO c</code></li>
<li><code>action4 x y :: IO a</code></li>
<li><code>x :: b</code>, <code>y :: c</code></li>
</ul></li>
<li>Quelques objets ont le type <code>IO a</code>, cela devrait vous aider à choisir. En particulier vous ne pouvez pas utiliser de fonctions pures directement ici. Pour utiliser des fonctions pures vous pourriez faire <code>action2 (pureFunction x)</code> par exemple.</li>
</ul>
</blockquote>
<p>Dans cette section, je vais expliquer comment utiliser lIO, pas comment ça marche. Vous verrez comment Haskell sépare les parties pures et impures du programme.</p>
<p>Ne vous arrêtez pas sur les détails de la syntaxe Les réponses viendront dans la section suivante.</p>
<p>Que cherchons-nous à faire?</p>
<blockquote>
<p>Demander une liste de nombres à lutilisateur. Afficher la somme de ces nombres.</p>
</blockquote>
<div class="codehighlight">
<div class="sourceCode" id="cb128"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb128-1" title="1"><span class="ot">toList ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb128-2" title="2">toList input <span class="ot">=</span> <span class="fu">read</span> (<span class="st">&quot;[&quot;</span> <span class="op">++</span> input <span class="op">++</span> <span class="st">&quot;]&quot;</span>)</a>
<a class="sourceLine" id="cb128-3" title="3"></a>
<a class="sourceLine" id="cb128-4" title="4">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb128-5" title="5"> <span class="fu">putStrLn</span> <span class="st">&quot;Enter a list of numbers (separated by comma):&quot;</span></a>
<a class="sourceLine" id="cb128-6" title="6"> input <span class="ot">&lt;-</span> <span class="fu">getLine</span></a>
<a class="sourceLine" id="cb128-7" title="7"> <span class="fu">print</span> <span class="op">$</span> <span class="fu">sum</span> (toList input)</a></code></pre></div>
</div>
<p>Il devrait être simple de comprendre le comportement de ce programme. Analysons les types en détails.</p>
<pre><code>putStrLn :: String -&gt; IO ()
getLine :: IO String
print :: Show a =&gt; a -&gt; IO ()</code></pre>
<p>Ou, de manièree plus intéressante, on remarque que chaque expression dans le bloc <code>do</code> est de type <code>IO a</code>.</p>
<pre>
main = do
putStrLn "Enter ... " :: <span class="high">IO ()</span>
getLine :: <span class="high">IO String</span>
print Something :: <span class="high">IO ()</span>
</pre>
<p>Nous devrions aussi prêter attention à leffet du symbole <code>&lt;-</code>.</p>
<pre><code>do
x &lt;- something</code></pre>
<p>Si <code>something :: IO a</code> alors <code>x :: a</code>.</p>
<p>Une autre remarque importante sur l<code>IO</code>: Toutes les lignes dun bloc <code>do</code> doivent être dune des deux formes suivantes&nbsp;:</p>
<pre><code>action1 :: IO a
-- in this case, generally a = ()</code></pre>
<p>ou</p>
<pre><code>value &lt;- action2 -- where
-- action2 :: IO b
-- value :: b</code></pre>
<p>Ces deux types de ligne correspondent à deux types différents de séquençage daction. La signification de cette phrase devrait être plus claire à la fin de la prochaine section.</p>
<p><a href="code/03_Hell/01_IO/01_progressive_io_example.lhs" class="cut">03_Hell/01_IO/<strong>01_progressive_io_example.lhs</strong> </a></p>
<hr />
<p><a href="code/03_Hell/01_IO/02_progressive_io_example.lhs" class="cut">03_Hell/01_IO/<strong>02_progressive_io_example.lhs</strong></a></p>
<p>Maintenant voyons comment ce programme se comporte. Par exemple, que ce passe-t-il si lutilisateur entre une mauvaise valeur? Essayons&nbsp;:</p>
<pre><code> % runghc 02_progressive_io_example.lhs
Enter a list of numbers (separated by comma):
foo
Prelude.read: no parse</code></pre>
<p>Argh! Un message derreur effrayant et un crash ! Notre première amélioration sera de répondre avec un message plus amical.</p>
<p>Pour faire cela, nous devons détecter que quelque chose sest mal passé. Voici un moyen de le faire : utiliser le type <code>Maybe</code>. Cest un type très utilisé en Haskell.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb134"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb134-1" title="1"><span class="kw">import</span> <span class="dt">Data.Maybe</span></a></code></pre></div>
</div>
<p>Mais quest-ce que cest ? <code>Maybe</code> est un type qui prend un paramètre. Sa définition est&nbsp;:</p>
<div class="sourceCode" id="cb135"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb135-1" title="1"><span class="kw">data</span> <span class="dt">Maybe</span> a <span class="ot">=</span> <span class="dt">Nothing</span> <span class="op">|</span> <span class="dt">Just</span> a</a></code></pre></div>
<p>Cest un bon moyen de dire quil y a eu une erreur en essayant de créer/évaluer une valeur. La fonction <code>maybeRead</code> en est un bon exemple. Cest une fonction similaire à <code>read</code><a href="#fn3" class="footnote-ref" id="fnref3"><sup>3</sup></a>, mais sil y a un problème, la valeur retournée est <code>Nothing</code>. Si la valeur est bonne, la valeur retournée est <code>Just &lt;la valeur&gt;</code>. Ne vous efforcez pas trop de comprendre cette fonction. Jutilise une fonction de plus bas niveau que <code>read</code> : <code>reads</code>.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb136"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb136-1" title="1"><span class="ot">maybeRead ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</a>
<a class="sourceLine" id="cb136-2" title="2">maybeRead s <span class="ot">=</span> <span class="kw">case</span> <span class="fu">reads</span> s <span class="kw">of</span></a>
<a class="sourceLine" id="cb136-3" title="3"> [(x,<span class="st">&quot;&quot;</span>)] <span class="ot">-&gt;</span> <span class="dt">Just</span> x</a>
<a class="sourceLine" id="cb136-4" title="4"> _ <span class="ot">-&gt;</span> <span class="dt">Nothing</span></a></code></pre></div>
</div>
<p>Maintenant, pour être plus lisible, on définit une fonction comme ceci : Si la chaîne a un mauvais format, elle retournera <code>Nothing</code>. Sinon, par exemple pour “1,2,3”, cela retournera <code>Just [1,2,3]</code>.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb137"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb137-1" title="1"><span class="ot">getListFromString ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb137-2" title="2">getListFromString str <span class="ot">=</span> maybeRead <span class="op">$</span> <span class="st">&quot;[&quot;</span> <span class="op">++</span> str <span class="op">++</span> <span class="st">&quot;]&quot;</span></a></code></pre></div>
</div>
<p>Nous avons juste à tester la valeur dans notre fonction principale.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb138"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb138-1" title="1"><span class="ot">main ::</span> <span class="dt">IO</span> ()</a>
<a class="sourceLine" id="cb138-2" title="2">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb138-3" title="3"> <span class="fu">putStrLn</span> <span class="st">&quot;Enter a list of numbers (separated by comma):&quot;</span></a>
<a class="sourceLine" id="cb138-4" title="4"> input <span class="ot">&lt;-</span> <span class="fu">getLine</span></a>
<a class="sourceLine" id="cb138-5" title="5"> <span class="kw">let</span> maybeList <span class="ot">=</span> getListFromString input <span class="kw">in</span></a>
<a class="sourceLine" id="cb138-6" title="6"> <span class="kw">case</span> maybeList <span class="kw">of</span></a>
<a class="sourceLine" id="cb138-7" title="7"> <span class="dt">Just</span> l <span class="ot">-&gt;</span> <span class="fu">print</span> (<span class="fu">sum</span> l)</a>
<a class="sourceLine" id="cb138-8" title="8"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">error</span> <span class="st">&quot;Bad format. Good Bye.&quot;</span></a></code></pre></div>
</div>
<p>En cas derreur, on affiche un joli message.</p>
<p>Notez que le type de chaque expression dans le bloc <code>do</code> de <code>main</code> reste de la forme <code>IO a</code>. La seule construction étrange est <code>error</code>. Disons juste que <code>error msg</code> prend le type nécessaire (ici, <code>IO ()</code>).</p>
<p>Une chose très importante à noter est le type de toutes les fonctions définies jusquici. Il ny a quune seule fonction qui contient <code>IO</code> dans son type : <code>main</code>. Cela signifie que <code>main</code> est impure. Mais <code>main</code> utilise <code>getListFromString</code>, qui, elle, est pure. Nous pouvons donc facilement repérer quelles fonctions sont pures et lesquelles sont impures, seulement en regardant leur type.</p>
<p>Pourquoi la pureté a-t-elle de limportance? Parmi ses nombreux avantages, en voici trois&nbsp;:</p>
<ul>
<li>Il est beaucoup plus facile de penser à du code pur quà du code impur.</li>
<li>La pureté vous protège de tous les bugs difficiles à reproduire dûs aux <a href="https://fr.wikipedia.org/wiki/Effet_de_bord_(informatique)">effets de bord</a>.</li>
<li>Vous pouvez évaluer des fonctions pures dans nimporte quel ordre ou en parallèle, sans prendre de risques.</li>
</ul>
<p>Cest pourquoi vous devriez mettre le plus de code possible dans des fonctions pures.</p>
<p><a href="code/03_Hell/01_IO/02_progressive_io_example.lhs" class="cut">03_Hell/01_IO/<strong>02_progressive_io_example.lhs</strong> </a></p>
<hr />
<p><a href="code/03_Hell/01_IO/03_progressive_io_example.lhs" class="cut">03_Hell/01_IO/<strong>03_progressive_io_example.lhs</strong></a></p>
<p>La prochaine étape sera de demander la liste de nombres à lutilisateur encore et encore jusquà ce quil entre une réponse valide.</p>
<p>Nous gardons la première partie&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb139"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb139-1" title="1"><span class="kw">import</span> <span class="dt">Data.Maybe</span></a>
<a class="sourceLine" id="cb139-2" title="2"></a>
<a class="sourceLine" id="cb139-3" title="3"><span class="ot">maybeRead ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</a>
<a class="sourceLine" id="cb139-4" title="4">maybeRead s <span class="ot">=</span> <span class="kw">case</span> <span class="fu">reads</span> s <span class="kw">of</span></a>
<a class="sourceLine" id="cb139-5" title="5"> [(x,<span class="st">&quot;&quot;</span>)] <span class="ot">-&gt;</span> <span class="dt">Just</span> x</a>
<a class="sourceLine" id="cb139-6" title="6"> _ <span class="ot">-&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb139-7" title="7"><span class="ot">getListFromString ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb139-8" title="8">getListFromString str <span class="ot">=</span> maybeRead <span class="op">$</span> <span class="st">&quot;[&quot;</span> <span class="op">++</span> str <span class="op">++</span> <span class="st">&quot;]&quot;</span></a></code></pre></div>
</div>
<p>Maintenant nous créons la fonction qui demandera une liste dentiers à lutilisateur jusquà ce que lentrée soit correcte</p>
<div class="codehighlight">
<div class="sourceCode" id="cb140"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb140-1" title="1"><span class="ot">askUser ::</span> <span class="dt">IO</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb140-2" title="2">askUser <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb140-3" title="3"> <span class="fu">putStrLn</span> <span class="st">&quot;Enter a list of numbers (separated by comma):&quot;</span></a>
<a class="sourceLine" id="cb140-4" title="4"> input <span class="ot">&lt;-</span> <span class="fu">getLine</span></a>
<a class="sourceLine" id="cb140-5" title="5"> <span class="kw">let</span> maybeList <span class="ot">=</span> getListFromString input <span class="kw">in</span></a>
<a class="sourceLine" id="cb140-6" title="6"> <span class="kw">case</span> maybeList <span class="kw">of</span></a>
<a class="sourceLine" id="cb140-7" title="7"> <span class="dt">Just</span> l <span class="ot">-&gt;</span> <span class="fu">return</span> l</a>
<a class="sourceLine" id="cb140-8" title="8"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> askUser</a></code></pre></div>
</div>
<p>Cette fonction est de type <code>IO [Integer]</code>. Cela signifie que la valeur récupérée est de type <code>[Integer</code>] et est le résultat dactions dE/S. Daucuns diront avec enthousiasme&nbsp;:</p>
<blockquote>
<p>«Cest un <code>[Integer]</code> dans un <code>IO</code></p>
</blockquote>
<p>Si vous voulez comprendre les détails derrière tout cela, vous devrez lire la prochaine section. Mais si vous voulez seulement <em>utiliser</em> lE/S, contentez-vous pratiquer un peu et rappelez-vous de penser aux types.</p>
<p>Finalement, notre fonction <code>main</code>est bien plus simple&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb141"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb141-1" title="1"><span class="ot">main ::</span> <span class="dt">IO</span> ()</a>
<a class="sourceLine" id="cb141-2" title="2">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb141-3" title="3"> list <span class="ot">&lt;-</span> askUser</a>
<a class="sourceLine" id="cb141-4" title="4"> <span class="fu">print</span> <span class="op">$</span> <span class="fu">sum</span> list</a></code></pre></div>
</div>
<p>Nous avons fini notre introduction à l<code>IO</code>. Cétait plutôt rapide. Voici les principales choses à retenir&nbsp;:</p>
<ul>
<li>Dans le bloc <code>do</code>, chaque expression doit avoir le type <code>IO a</code>. Vous êtes donc limité quant au panel dexpression disponibles. Par exemple, <code>getLine</code>, <code>print</code>, <code>putStrLn</code>, etc…</li>
<li>Essayez dexternaliser le plus possible les fonctions pures.</li>
<li>le type <code>IO a</code> signifie : une <em>action</em> dE/S qui retourne un élément de type a. L<code>IO</code> représente des actions; sous le capot, <code>IO a</code> est le type dune fonction. Lisez la prochaine section si vous êtes curieux.</li>
</ul>
<p>Si vous pratiquez un peu, vous devriez être capable d<em>utiliser</em> l<code>IO</code>.</p>
<blockquote>
<p>-Exercices_:</p>
<ul>
<li>Écrivez un programme qui additionne tous ses arguments. Utilisez la fonction <code>getArgs</code>.</li>
</ul>
</blockquote>
<p><a href="code/03_Hell/01_IO/03_progressive_io_example.lhs" class="cut">03_Hell/01_IO/<strong>03_progressive_io_example.lhs</strong> </a></p>
<h3 id="io-trick-explained">
Le truc des IO révélé
</h3>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/magritte_pipe.jpg" alt="Magritte, ceci n" />
</div>
<blockquote>
<p>Voici un <span class="sc"><abbr title="Trop long; pas lu">tlpl</abbr>: </span> pour cette section.</p>
<p>Pour séparer les parties pures et impures, <code>main</code> est définie comme une fonction. qui modifie létat du monde.</p>
<pre><code>main :: World -&gt; World</code></pre>
<p>Une fonction aura des effets de bord si elle a ce type. Mais regardez cette fonction <code>main</code> typique:</p>
<pre><code>
main w0 =
let (v1,w1) = action1 w0 in
let (v2,w2) = action2 v1 w1 in
let (v3,w3) = action3 v2 w2 in
action4 v3 w3</code></pre>
<p>Nous avons beaucoup délements temporaires (ici, <code>w1</code>, <code>w2</code> et <code>w3</code>) qui doivent être passés à laction suivante.</p>
<p>Nous créons une fonction <code>bind</code> ou <code>(&gt;&gt;=)</code>. Avec <code>bind</code> nous navons plus besoin de noms temporaires.</p>
<pre><code>main =
action1 &gt;&gt;= action2 &gt;&gt;= action3 &gt;&gt;= action4</code></pre>
<p>Bonus: Haskell a du sucre syntaxique&nbsp;:</p>
<pre><code>main = do
v1 &lt;- action1
v2 &lt;- action2 v1
v3 &lt;- action3 v2
action4 v3</code></pre>
</blockquote>
<p>Pourquoi avons-nous utilisé cette syntaxe étrange, et quel est exactement le type <code>IO</code>? Cela peut sembler un peu magique.</p>
<p>Pour linstant, oublions les parties pures de notre programme, et concentrons-nous sur les parties impures:</p>
<div class="sourceCode" id="cb146"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb146-1" title="1"><span class="ot">askUser ::</span> <span class="dt">IO</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb146-2" title="2">askUser <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb146-3" title="3"> <span class="fu">putStrLn</span> <span class="st">&quot;Enter a list of numbers (separated by commas):&quot;</span></a>
<a class="sourceLine" id="cb146-4" title="4"> input <span class="ot">&lt;-</span> <span class="fu">getLine</span></a>
<a class="sourceLine" id="cb146-5" title="5"> <span class="kw">let</span> maybeList <span class="ot">=</span> getListFromString input <span class="kw">in</span></a>
<a class="sourceLine" id="cb146-6" title="6"> <span class="kw">case</span> maybeList <span class="kw">of</span></a>
<a class="sourceLine" id="cb146-7" title="7"> <span class="dt">Just</span> l <span class="ot">-&gt;</span> <span class="fu">return</span> l</a>
<a class="sourceLine" id="cb146-8" title="8"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> askUser</a>
<a class="sourceLine" id="cb146-9" title="9"></a>
<a class="sourceLine" id="cb146-10" title="10"><span class="ot">main ::</span> <span class="dt">IO</span> ()</a>
<a class="sourceLine" id="cb146-11" title="11">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb146-12" title="12"> list <span class="ot">&lt;-</span> askUser</a>
<a class="sourceLine" id="cb146-13" title="13"> <span class="fu">print</span> <span class="op">$</span> <span class="fu">sum</span> list</a></code></pre></div>
<p>Première remarque : on dirait de limpératif. Haskell est assez puissant pour faire sembler impératif du code impur. Par exemple, si vous le vouliez vous pourriez créer une boucle <code>while</code> en Haskell. En fait, pour utiliser les <code>IO</code>, le style impératif est en général plus approprié.</p>
<p>Mais vous devriez avoir remarqué que la notation est inhabituelle. Voici pourquoi, en détail.</p>
<p>Dans un langage impur, létat du monde peut être vu comme une énorme variable globale cachée. Cette variable cachée est accessible par toutes les fonctions du langage. Par exemple, vous pouvez lire et écrire dans un fichier avec nimporte quelle fonction. Le fait que le fichier putatif existe ou non est une éventualité qui relève des états possibles que le monde courant peut prendre.</p>
<p>En Haskell létat courant du monde nest pas caché. Au contraire, il est dit <em>explicitement</em> que <code>main</code> est une fonction qui change <em>potentiellement</em> létat du monde. Son type est donc quelque chose comme&nbsp;:</p>
<div class="sourceCode" id="cb147"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb147-1" title="1"><span class="ot">main ::</span> <span class="dt">World</span> <span class="ot">-&gt;</span> <span class="dt">World</span></a></code></pre></div>
<p>Les fonctions ne sont pas toutes susceptibles de modifier cette variable. Celle qui peuvent la modifier sont impures. Les fonctions qui ne peuvent pas agir sur la variable sont pures<a href="#fn4" class="footnote-ref" id="fnref4"><sup>4</sup></a>.</p>
<p>Haskell considère létat du monde comme une variable à passer à <code>main</code>. Mais son type réel est plus proche de celui ci<a href="#fn5" class="footnote-ref" id="fnref5"><sup>5</sup></a>&nbsp;:</p>
<div class="sourceCode" id="cb148"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb148-1" title="1"><span class="ot">main ::</span> <span class="dt">World</span> <span class="ot">-&gt;</span> ((),<span class="dt">World</span>)</a></code></pre></div>
<p>Le type <code>()</code> est le type “unit”. Rien à voir ici.</p>
<p>Maintenant réécrivons notre fonction <code>main</code> avec cela à lesprit&nbsp;:</p>
<div class="sourceCode" id="cb149"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb149-1" title="1">main w0 <span class="ot">=</span></a>
<a class="sourceLine" id="cb149-2" title="2"> <span class="kw">let</span> (list,w1) <span class="ot">=</span> askUser w0 <span class="kw">in</span></a>
<a class="sourceLine" id="cb149-3" title="3"> <span class="kw">let</span> (x,w2) <span class="ot">=</span> <span class="fu">print</span> (<span class="fu">sum</span> list,w1) <span class="kw">in</span></a>
<a class="sourceLine" id="cb149-4" title="4"> x</a></code></pre></div>
<p>Dabord, on remarque que toutes les fonctions avec des effets de bord doivent avoir le type&nbsp;:</p>
<div class="sourceCode" id="cb150"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb150-1" title="1"><span class="dt">World</span> <span class="ot">-&gt;</span> (a,<span class="dt">World</span>)</a></code></pre></div>
<p><code>a</code> est le type du résultat. Par exemple, une fonction <code>getChar</code> aura le type `World -&gt; (Char, World).</p>
<p>Une autre chose à noter est lastuce pour corriger lordre dévaluation. En Haskell, pour évaluer <code>f a b</code>, vous avez lembarras du choix&nbsp;:</p>
<ul>
<li>évaluer dabord <code>a</code> puis <code>b</code> puis <code>f a b</code></li>
<li>évaluer dabord <code>b</code> puis <code>a</code> puis <code>f a b</code></li>
<li>évaluer <code>a</code> et <code>b</code> parallèlement, puis <code>f a b</code></li>
</ul>
<p>Cela vient du fait que nous avons recours à une partie pure du langage.</p>
<p>Maintenant, si vous regardez la fonction <code>main</code>, vous voyez tout de suite quil faut évaluer la première ligne avant la seconde, car pour évaluer la seconde ligne vous devez utliser un paramètre donné suite à lévaluation de la première ligne.</p>
<p>Cette astuce fonctionne très bien. Le compilateur donnera à chaque étape un pointeur sur lid du nouveau monde courant. En réalité, <code>print</code> sera évaluée comme suit&nbsp;:</p>
<ul>
<li>Écrit quelque chose sur lécran</li>
<li>Modifie lid du monde</li>
<li>renvoyer <code>((), id du nouveau monde)</code>.</li>
</ul>
<p>Maintenant, si jetez un oeil au style de la fonction <code>main</code>, vous remarquerez quil est clairement peu commode. Essayons de faire la même chose avec la fonction <code>askUser</code>&nbsp;:</p>
<div class="sourceCode" id="cb151"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb151-1" title="1"><span class="ot">askUser ::</span> <span class="dt">World</span> <span class="ot">-&gt;</span> ([<span class="dt">Integer</span>],<span class="dt">World</span>)</a></code></pre></div>
<p>Avant&nbsp;:</p>
<div class="sourceCode" id="cb152"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb152-1" title="1"><span class="ot">askUser ::</span> <span class="dt">IO</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb152-2" title="2">askUser <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb152-3" title="3"> <span class="fu">putStrLn</span> <span class="st">&quot;Enter a list of numbers:&quot;</span></a>
<a class="sourceLine" id="cb152-4" title="4"> input <span class="ot">&lt;-</span> <span class="fu">getLine</span></a>
<a class="sourceLine" id="cb152-5" title="5"> <span class="kw">let</span> maybeList <span class="ot">=</span> getListFromString input <span class="kw">in</span></a>
<a class="sourceLine" id="cb152-6" title="6"> <span class="kw">case</span> maybeList <span class="kw">of</span></a>
<a class="sourceLine" id="cb152-7" title="7"> <span class="dt">Just</span> l <span class="ot">-&gt;</span> <span class="fu">return</span> l</a>
<a class="sourceLine" id="cb152-8" title="8"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> askUser</a></code></pre></div>
<p>Après&nbsp;:</p>
<div class="sourceCode" id="cb153"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb153-1" title="1">askUser w0 <span class="ot">=</span></a>
<a class="sourceLine" id="cb153-2" title="2"> <span class="kw">let</span> (_,w1) <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">&quot;Enter a list of numbers:&quot;</span> <span class="kw">in</span></a>
<a class="sourceLine" id="cb153-3" title="3"> <span class="kw">let</span> (input,w2) <span class="ot">=</span> <span class="fu">getLine</span> w1 <span class="kw">in</span></a>
<a class="sourceLine" id="cb153-4" title="4"> <span class="kw">let</span> (l,w3) <span class="ot">=</span> <span class="kw">case</span> getListFromString input <span class="kw">of</span></a>
<a class="sourceLine" id="cb153-5" title="5"> <span class="dt">Just</span> l <span class="ot">-&gt;</span> (l,w2)</a>
<a class="sourceLine" id="cb153-6" title="6"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> askUser w2</a>
<a class="sourceLine" id="cb153-7" title="7"> <span class="kw">in</span></a>
<a class="sourceLine" id="cb153-8" title="8"> (l,w3)</a></code></pre></div>
<p>Cest similaire, mais peu commode. Voyez-vous toutes ces variables temporaires <code>w?</code>.</p>
<p>Voici la leçon : une implémentation naïve des IO dans les langages fonctionnels purs serait maladroite !</p>
<p>Heureusement, il y a un meilleur moyen de résoudre ce problème. Nous voyons un motif. Chaque ligne est de la forme&nbsp;:</p>
<div class="sourceCode" id="cb154"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb154-1" title="1"><span class="kw">let</span> (y,w') <span class="ot">=</span> action x w <span class="kw">in</span></a></code></pre></div>
<p>Même si pour certaines lignes largument <code>x</code> nest pas nécessaire. La sortie est un couple, <code>(answer, newWorldValue)</code>. Chaque fonction <code>f</code> doit avoir un type similaire à&nbsp;:</p>
<div class="sourceCode" id="cb155"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb155-1" title="1"><span class="ot">f ::</span> <span class="dt">World</span> <span class="ot">-&gt;</span> (a,<span class="dt">World</span>)</a></code></pre></div>
<p>Et ce nest pas fini, nous pouvons aussi remarquer que nous suivons toujours le même motif&nbsp;:</p>
<div class="sourceCode" id="cb156"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb156-1" title="1"><span class="kw">let</span> (y,w1) <span class="ot">=</span> action1 w0 <span class="kw">in</span></a>
<a class="sourceLine" id="cb156-2" title="2"><span class="kw">let</span> (z,w2) <span class="ot">=</span> action2 w1 <span class="kw">in</span></a>
<a class="sourceLine" id="cb156-3" title="3"><span class="kw">let</span> (t,w3) <span class="ot">=</span> action3 w2 <span class="kw">in</span></a>
<a class="sourceLine" id="cb156-4" title="4"><span class="op">...</span></a></code></pre></div>
<p>Chaque action peut prendre de 0 à n paramètres. Et en particulier, chaque action prend comme paramètre le résultat de la ligne précédente.</p>
<p>Par exemple, nous pourrions aussi avoir&nbsp;:</p>
<div class="sourceCode" id="cb157"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb157-1" title="1"><span class="kw">let</span> (_,w1) <span class="ot">=</span> action1 x w0 <span class="kw">in</span></a>
<a class="sourceLine" id="cb157-2" title="2"><span class="kw">let</span> (z,w2) <span class="ot">=</span> action2 w1 <span class="kw">in</span></a>
<a class="sourceLine" id="cb157-3" title="3"><span class="kw">let</span> (_,w3) <span class="ot">=</span> action3 z w2 <span class="kw">in</span></a>
<a class="sourceLine" id="cb157-4" title="4"><span class="op">...</span></a></code></pre></div>
<p>Avec, bien entendu, <code>actionN w :: (World) -&gt; (a,World)</code>.</p>
<blockquote>
<p>IMPORTANT: Il y a seulement 2 schémas importants à considérer&nbsp;:</p>
<pre><code>let (x,w1) = action1 w0 in
let (y,w2) = action2 x w1 in</code></pre>
<p>et</p>
<pre><code>let (_,w1) = action1 w0 in
let (y,w2) = action2 w1 in</code></pre>
</blockquote>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/jocker_pencil_trick.jpg" alt="Jocker pencil trick" class="left" />
</div>
<p>Maintenant, préparez-vous pour un petit tour de magie ! Faisons disparaître les variables temporaires de monde courant. Nous allons <code>attacher</code> (<em>NDT: <code>bind</code> en anglais</em>) les deux lignes. Définissons la fonction <code>bind</code>. Son type est assez intimidant au début&nbsp;:</p>
<div class="sourceCode" id="cb160"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb160-1" title="1"><span class="ot">bind ::</span> (<span class="dt">World</span> <span class="ot">-&gt;</span> (a,<span class="dt">World</span>))</a>
<a class="sourceLine" id="cb160-2" title="2"> <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> (<span class="dt">World</span> <span class="ot">-&gt;</span> (b,<span class="dt">World</span>)))</a>
<a class="sourceLine" id="cb160-3" title="3"> <span class="ot">-&gt;</span> (<span class="dt">World</span> <span class="ot">-&gt;</span> (b,<span class="dt">World</span>))</a></code></pre></div>
<p>Mais gardez en tête que <code>(World -&gt; (a,World))</code> est le type dune action dIO. Renommons-le pour plus de clarté&nbsp;:</p>
<div class="sourceCode" id="cb161"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb161-1" title="1"><span class="kw">type</span> <span class="dt">IO</span> a <span class="ot">=</span> <span class="dt">World</span> <span class="ot">-&gt;</span> (a, <span class="dt">World</span>)</a></code></pre></div>
<p>Quelques exemples de fonctions&nbsp;:</p>
<div class="sourceCode" id="cb162"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb162-1" title="1"><span class="fu">getLine</span><span class="ot"> ::</span> <span class="dt">IO</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb162-2" title="2"><span class="fu">print</span><span class="ot"> ::</span> <span class="dt">Show</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</a></code></pre></div>
<p><code>getLine</code> est une action dE/S qui prend le monde en paramètre et retourne un couple <code>(String, World)</code>. Cela peut être résumé par : <code>getLine</code> est de type <code>IO String</code>, que nous pouvons voir comme une action dE/S qui retournera une chaîne de caractères “dans une E/S”.</p>
<p>La fonction <code>print</code> est elle aussi intéressante. Elle prend un argument qui peut être montré avec <code>show</code>. En fait, elle prend deux arguments. Le premier est la valeur et le deuxième est létat du monde. Elle retourne un couple de type <code>((), World)</code>. Cela signifie quelle change létat du monde, mais ne produit pas dautre donnée.</p>
<p>Ce nouveau type <code>IO a</code> nous aide à simplifier le type de <code>bind</code>&nbsp;:</p>
<div class="sourceCode" id="cb163"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb163-1" title="1"><span class="ot">bind ::</span> <span class="dt">IO</span> a</a>
<a class="sourceLine" id="cb163-2" title="2"> <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">IO</span> b)</a>
<a class="sourceLine" id="cb163-3" title="3"> <span class="ot">-&gt;</span> <span class="dt">IO</span> b</a></code></pre></div>
<p>Cela dit que <code>bind</code> prend deux actions dE/S en paramètres et retourne une autre action dE/S.</p>
<p>Maintenant, rappelez-vous des motifs <em>importants</em>. Le premier était&nbsp;:</p>
<div class="sourceCode" id="cb164"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb164-1" title="1">pattern1 w0 <span class="ot">=</span> </a>
<a class="sourceLine" id="cb164-2" title="2"> <span class="kw">let</span> (x,w1) <span class="ot">=</span> action1 w0 <span class="kw">in</span></a>
<a class="sourceLine" id="cb164-3" title="3"> <span class="kw">let</span> (y,w2) <span class="ot">=</span> action2 x w1 <span class="kw">in</span></a>
<a class="sourceLine" id="cb164-4" title="4"> (y,w2)</a></code></pre></div>
<p>Voyez les types&nbsp;:</p>
<div class="sourceCode" id="cb165"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb165-1" title="1"><span class="ot">action1 ::</span> <span class="dt">IO</span> a</a>
<a class="sourceLine" id="cb165-2" title="2"><span class="ot">action2 ::</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> b</a>
<a class="sourceLine" id="cb165-3" title="3"><span class="ot">pattern1 ::</span> <span class="dt">IO</span> b</a></code></pre></div>
<p>Cela ne vous semble-t-il pas familier ?</p>
<div class="sourceCode" id="cb166"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb166-1" title="1">(bind action1 action2) w0 <span class="ot">=</span></a>
<a class="sourceLine" id="cb166-2" title="2"> <span class="kw">let</span> (x, w1) <span class="ot">=</span> action1 w0</a>
<a class="sourceLine" id="cb166-3" title="3"> (y, w2) <span class="ot">=</span> action2 x w1</a>
<a class="sourceLine" id="cb166-4" title="4"> <span class="kw">in</span> (y, w2)</a></code></pre></div>
<p>Lidée est de cacher largument <code>World</code> avec cette fonction. Allons-y ! Par exemple si nous avions voulu simuler&nbsp;:</p>
<div class="sourceCode" id="cb167"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb167-1" title="1"><span class="kw">let</span> (line1, w1) <span class="ot">=</span> <span class="fu">getLine</span> w0 <span class="kw">in</span></a>
<a class="sourceLine" id="cb167-2" title="2"><span class="kw">let</span> ((), w2) <span class="ot">=</span> <span class="fu">print</span> line1 <span class="kw">in</span></a>
<a class="sourceLine" id="cb167-3" title="3">((), w2)</a></code></pre></div>
<p>Maintenant, en utilisant la fonction <code>bind</code>&nbsp;:</p>
<div class="sourceCode" id="cb168"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb168-1" title="1">(res, w2) <span class="ot">=</span> (bind <span class="fu">getLine</span> <span class="fu">print</span>) w0</a></code></pre></div>
<p>Comme <code>print</code> est de type <code>Show a =&gt; a -&gt; (World -&gt; ((), World))</code>, nous savons que <code>res = ()</code> (type <code>unit</code>) Si vous ne voyez pas ce qui est magique ici, essayons avec trois lignes cette fois.</p>
<div class="sourceCode" id="cb169"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb169-1" title="1"><span class="kw">let</span> (line1,w1) <span class="ot">=</span> <span class="fu">getLine</span> w0 <span class="kw">in</span></a>
<a class="sourceLine" id="cb169-2" title="2"><span class="kw">let</span> (line2,w2) <span class="ot">=</span> <span class="fu">getLine</span> w1 <span class="kw">in</span></a>
<a class="sourceLine" id="cb169-3" title="3"><span class="kw">let</span> ((),w3) <span class="ot">=</span> <span class="fu">print</span> (line1 <span class="op">++</span> line2) <span class="kw">in</span></a>
<a class="sourceLine" id="cb169-4" title="4">((),w3)</a></code></pre></div>
<p>Qui est équivalent à&nbsp;:</p>
<div class="sourceCode" id="cb170"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb170-1" title="1">(res,w3) <span class="ot">=</span> (bind <span class="fu">getLine</span> (\line1 <span class="ot">-&gt;</span></a>
<a class="sourceLine" id="cb170-2" title="2"> (bind <span class="fu">getLine</span> (\line2 <span class="ot">-&gt;</span></a>
<a class="sourceLine" id="cb170-3" title="3"> <span class="fu">print</span> (line1 <span class="op">++</span> line2))))) w0</a></code></pre></div>
<p>Avez-vous remarqué quelque chose ? Oui, aucune variable <code>World</code> temporaire nest utilisée ! Cest <em>MA</em>._GIQUE_.</p>
<p>Nous pouvons utiliser une meilleure notation. Utilisons <code>(&gt;&gt;=)</code> au lieu de <code>bind</code>. <code>(&gt;&gt;=)</code> est une fonction infixe, comme <code>(+)</code>; pour mémoire : <code>3 + 4 ⇔ (+) 3 4</code></p>
<div class="sourceCode" id="cb171"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb171-1" title="1">(res,w3) <span class="ot">=</span> (<span class="fu">getLine</span> <span class="op">&gt;&gt;=</span></a>
<a class="sourceLine" id="cb171-2" title="2"> (\line1 <span class="ot">-&gt;</span> <span class="fu">getLine</span> <span class="op">&gt;&gt;=</span></a>
<a class="sourceLine" id="cb171-3" title="3"> (\line2 <span class="ot">-&gt;</span> <span class="fu">print</span> (line1 <span class="op">++</span> line2)))) w0</a></code></pre></div>
<p>Ho Ho Ho! Joyeux Noël ! fr; Haskell a confectionné du sucre syntaxique pour vous&nbsp;:</p>
<div class="sourceCode" id="cb172"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb172-1" title="1"><span class="kw">do</span></a>
<a class="sourceLine" id="cb172-2" title="2"> x <span class="ot">&lt;-</span> action1</a>
<a class="sourceLine" id="cb172-3" title="3"> y <span class="ot">&lt;-</span> action2</a>
<a class="sourceLine" id="cb172-4" title="4"> z <span class="ot">&lt;-</span> action3</a>
<a class="sourceLine" id="cb172-5" title="5"> <span class="op">...</span></a></code></pre></div>
<p>Est remplacé par&nbsp;:</p>
<div class="sourceCode" id="cb173"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb173-1" title="1">action1 <span class="op">&gt;&gt;=</span> (\x <span class="ot">-&gt;</span></a>
<a class="sourceLine" id="cb173-2" title="2">action2 <span class="op">&gt;&gt;=</span> (\y <span class="ot">-&gt;</span></a>
<a class="sourceLine" id="cb173-3" title="3">action3 <span class="op">&gt;&gt;=</span> (\z <span class="ot">-&gt;</span></a>
<a class="sourceLine" id="cb173-4" title="4"><span class="op">...</span></a>
<a class="sourceLine" id="cb173-5" title="5">)))</a></code></pre></div>
<p>Remarquez que vous pouvez utliser <code>x</code> dans <code>action2</code> et <code>x</code> et <code>y</code> dans <code>action3</code>.</p>
<p>Mais que se passe-t-il pour les lignes qui nutilisent pas le <code>&lt;-</code> ? Facile, une autre fonction <code>blindBind</code>&nbsp;:</p>
<div class="sourceCode" id="cb174"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb174-1" title="1"><span class="ot">blindBind ::</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> b <span class="ot">-&gt;</span> <span class="dt">IO</span> b</a>
<a class="sourceLine" id="cb174-2" title="2">blindBind action1 action2 w0 <span class="ot">=</span></a>
<a class="sourceLine" id="cb174-3" title="3"> bind action (\_ <span class="ot">-&gt;</span> action2) w0</a></code></pre></div>
<p>Je nai pas simplifié cette définition pour plus de clarté. Bien sûr, nous pouvons utiliser une meilleure notation avec lopérateur <code>(&gt;&gt;)</code>.</p>
<p>Et</p>
<div class="sourceCode" id="cb175"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb175-1" title="1"><span class="kw">do</span></a>
<a class="sourceLine" id="cb175-2" title="2"> action1</a>
<a class="sourceLine" id="cb175-3" title="3"> action2</a>
<a class="sourceLine" id="cb175-4" title="4"> action3</a></code></pre></div>
<p>Devient</p>
<div class="sourceCode" id="cb176"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb176-1" title="1">action1 <span class="op">&gt;&gt;</span></a>
<a class="sourceLine" id="cb176-2" title="2">action2 <span class="op">&gt;&gt;</span></a>
<a class="sourceLine" id="cb176-3" title="3">action3</a></code></pre></div>
<p>Enfin, une autre fonction est plutôt utile.</p>
<div class="sourceCode" id="cb177"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb177-1" title="1"><span class="ot">putInIO ::</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> a</a>
<a class="sourceLine" id="cb177-2" title="2">putInIO x <span class="ot">=</span> <span class="dt">IO</span> (\w <span class="ot">-&gt;</span> (x,w))</a></code></pre></div>
<p>Dune manière générale, cest une façon de mettre des valeurs pures dans le “contexte dE/S”. Le nom général pour <code>putInIO</code> est <code>return</code>. Cest un plutôt un mauvais nom lorsque vous commencez à programmer en Haskell. <code>return</code> est très différent de ce à quoi vous pourriez être habitué.</p>
<hr />
<p><a href="code/03_Hell/01_IO/21_Detailled_IO.lhs" class="cut">03_Hell/01_IO/<strong>21_Detailled_IO.lhs</strong></a></p>
<p>Pour finir, traduisons notre exemple&nbsp;:</p>
<div class="sourceCode" id="cb178"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb178-1" title="1"></a>
<a class="sourceLine" id="cb178-2" title="2"><span class="ot">askUser ::</span> <span class="dt">IO</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb178-3" title="3">askUser <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb178-4" title="4"> <span class="fu">putStrLn</span> <span class="st">&quot;Enter a list of numbers (separated by commas):&quot;</span></a>
<a class="sourceLine" id="cb178-5" title="5"> input <span class="ot">&lt;-</span> <span class="fu">getLine</span></a>
<a class="sourceLine" id="cb178-6" title="6"> <span class="kw">let</span> maybeList <span class="ot">=</span> getListFromString input <span class="kw">in</span></a>
<a class="sourceLine" id="cb178-7" title="7"> <span class="kw">case</span> maybeList <span class="kw">of</span></a>
<a class="sourceLine" id="cb178-8" title="8"> <span class="dt">Just</span> l <span class="ot">-&gt;</span> <span class="fu">return</span> l</a>
<a class="sourceLine" id="cb178-9" title="9"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> askUser</a>
<a class="sourceLine" id="cb178-10" title="10"></a>
<a class="sourceLine" id="cb178-11" title="11"><span class="ot">main ::</span> <span class="dt">IO</span> ()</a>
<a class="sourceLine" id="cb178-12" title="12">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb178-13" title="13"> list <span class="ot">&lt;-</span> askUser</a>
<a class="sourceLine" id="cb178-14" title="14"> <span class="fu">print</span> <span class="op">$</span> <span class="fu">sum</span> list</a></code></pre></div>
<p>Se traduit en&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb179"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb179-1" title="1"><span class="kw">import</span> <span class="dt">Data.Maybe</span></a>
<a class="sourceLine" id="cb179-2" title="2"></a>
<a class="sourceLine" id="cb179-3" title="3"><span class="ot">maybeRead ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</a>
<a class="sourceLine" id="cb179-4" title="4">maybeRead s <span class="ot">=</span> <span class="kw">case</span> <span class="fu">reads</span> s <span class="kw">of</span></a>
<a class="sourceLine" id="cb179-5" title="5"> [(x,<span class="st">&quot;&quot;</span>)] <span class="ot">-&gt;</span> <span class="dt">Just</span> x</a>
<a class="sourceLine" id="cb179-6" title="6"> _ <span class="ot">-&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb179-7" title="7"><span class="ot">getListFromString ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb179-8" title="8">getListFromString str <span class="ot">=</span> maybeRead <span class="op">$</span> <span class="st">&quot;[&quot;</span> <span class="op">++</span> str <span class="op">++</span> <span class="st">&quot;]&quot;</span></a>
<a class="sourceLine" id="cb179-9" title="9"><span class="ot">askUser ::</span> <span class="dt">IO</span> [<span class="dt">Integer</span>]</a>
<a class="sourceLine" id="cb179-10" title="10">askUser <span class="ot">=</span> </a>
<a class="sourceLine" id="cb179-11" title="11"> <span class="fu">putStrLn</span> <span class="st">&quot;Enter a list of numbers (sep. by commas):&quot;</span> <span class="op">&gt;&gt;</span></a>
<a class="sourceLine" id="cb179-12" title="12"> <span class="fu">getLine</span> <span class="op">&gt;&gt;=</span> \input <span class="ot">-&gt;</span></a>
<a class="sourceLine" id="cb179-13" title="13"> <span class="kw">let</span> maybeList <span class="ot">=</span> getListFromString input <span class="kw">in</span></a>
<a class="sourceLine" id="cb179-14" title="14"> <span class="kw">case</span> maybeList <span class="kw">of</span></a>
<a class="sourceLine" id="cb179-15" title="15"> <span class="dt">Just</span> l <span class="ot">-&gt;</span> <span class="fu">return</span> l</a>
<a class="sourceLine" id="cb179-16" title="16"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> askUser</a>
<a class="sourceLine" id="cb179-17" title="17"></a>
<a class="sourceLine" id="cb179-18" title="18"><span class="ot">main ::</span> <span class="dt">IO</span> ()</a>
<a class="sourceLine" id="cb179-19" title="19">main <span class="ot">=</span> askUser <span class="op">&gt;&gt;=</span></a>
<a class="sourceLine" id="cb179-20" title="20"> \list <span class="ot">-&gt;</span> <span class="fu">print</span> <span class="op">$</span> <span class="fu">sum</span> list</a></code></pre></div>
</div>
<p>Vous pouvez compiler ce code pour vérifier quil marche.</p>
<p>Imaginez à quoi il ressemblerait sans le <code>(&gt;&gt;)</code> et <code>(&gt;&gt;=)</code>.</p>
<p><a href="code/03_Hell/01_IO/21_Detailled_IO.lhs" class="cut">03_Hell/01_IO/<strong>21_Detailled_IO.lhs</strong> </a></p>
<hr />
<p><a href="code/03_Hell/02_Monads/10_Monads.lhs" class="cut">03_Hell/02_Monads/<strong>10_Monads.lhs</strong></a></p>
<h3 id="monads">
Les monades
</h3>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/dali_reve.jpg" alt="Dali, reve. It represents a weapon out of the mouth of a tiger, itself out of the mouth of another tiger, itself out of the mouth of a fish itself out of a grenade. I could have choosen a picture of the Human centipede as it is a very good representation of what a monad really is. But just to think about it, I find this disgusting and that wasn" />
</div>
<p>Maintenant le secret peut être dévoilé : <code>IO</code> est une <em>monade</em>. Être une monade signifie que vous avez accès à du sucre syntaxique avec la notation <code>do</code>. Mais principalement, vous avez accès à un motif de codage qui tempérera le flux de votre code.</p>
<blockquote>
<p><strong>Remarques importantes</strong>&nbsp;:</p>
<ul>
<li>Le monades nont pas forcément quoi que ce soit à voir avec les effets de bord ! Il y a beaucoup de monades <em>pures</em>.</li>
<li>Les monades concernent plus le séquençage.</li>
</ul>
</blockquote>
<p>En Haskell, <code>Monad</code> est une classe de type. Pour être une instance dune classe de type, vous devez fournir les fonctions <code>(&gt;&gt;=)</code> et <code>return</code>. La fonction <code>(&gt;&gt;)</code> est dérivée de <code>(&gt;&gt;=)</code>. Voici commment la classe de type <code>Monad</code> est déclarée (grosso modo)&nbsp;:</p>
<div class="sourceCode" id="cb180"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb180-1" title="1"><span class="kw">class</span> <span class="dt">Monad</span> m <span class="kw">where</span></a>
<a class="sourceLine" id="cb180-2" title="2"><span class="ot"> (&gt;&gt;=) ::</span> m a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> m b</a>
<a class="sourceLine" id="cb180-3" title="3"><span class="ot"> return ::</span> a <span class="ot">-&gt;</span> m a</a>
<a class="sourceLine" id="cb180-4" title="4"></a>
<a class="sourceLine" id="cb180-5" title="5"><span class="ot"> (&gt;&gt;) ::</span> m a <span class="ot">-&gt;</span> m b <span class="ot">-&gt;</span> m b</a>
<a class="sourceLine" id="cb180-6" title="6"> f <span class="op">&gt;&gt;</span> g <span class="ot">=</span> f <span class="op">&gt;&gt;=</span> \_ <span class="ot">-&gt;</span> g</a>
<a class="sourceLine" id="cb180-7" title="7"></a>
<a class="sourceLine" id="cb180-8" title="8"> <span class="co">-- Vous pouvez ignorer cette fonction généralement,</span></a>
<a class="sourceLine" id="cb180-9" title="9"> <span class="co">-- je crois qu'elle existe pour des raisons historiques</span></a>
<a class="sourceLine" id="cb180-10" title="10"><span class="ot"> fail ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m a</a>
<a class="sourceLine" id="cb180-11" title="11"> <span class="fu">fail</span> <span class="ot">=</span> <span class="fu">error</span></a></code></pre></div>
<blockquote>
<p>Remarques&nbsp;:</p>
<ul>
<li>le mot-clé <code>class</code> nest pas votre ami. Une classe en Haskell <em>nest pas</em> du même genre que celle des langages orientés-objet. Elles ont beaucoup de similarités avec les interfaces de Java. Un meilleur mot aurait été <code>typeClass</code>, ce qui signifierait un ensemble de types. Pour quun type appartienne à une classe, toutes les fonctions de cette classe doivent être fournies pour ce type.</li>
<li>Dans cet exemple particulier de classe de type, le type <code>m</code> doit être un type qui prend un argument. par exemple <code>IO a</code>, mais aussi <code>Maybe a</code>, <code>[a]</code>, etc…</li>
<li>Pour être une monade utile, votre fonction doit obéir à quelques règles. Si votre construction nobéit pas à ces règles, des choses étranges pourraient se produire :</li>
</ul>
</blockquote>
<blockquote>
<pre><code>return a &gt;&gt;= k == k a
m &gt;&gt;= return == m
m &gt;&gt;= (\x -&gt; k x &gt;&gt;= h) == (m &gt;&gt;= k) &gt;&gt;= h</code></pre>
</blockquote>
<h4 id="maybe-monad">
Maybe est une monade
</h4>
<p>Il y a beaucoup de types différents qui sont des instances de <code>Monad</code>. Lun des plus faciles à décrire est <code>Maybe</code>. Si vous avez une séquence de valeurs <code>Maybe</code>, vous pouvez utiliser les monades pour les manipuler. Cest particulièrement utile pour enlever des constructions <code>if..then..else..</code> trop nombreuses.</p>
<p>Imaginez une opération bancaire complexe. Vous êtes éligible pour gagner 700€ seulement si vous pouvez effectuer une liste dopérations sans tomber en dessous de zéro.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb182"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb182-1" title="1">deposit value account <span class="ot">=</span> account <span class="op">+</span> value</a>
<a class="sourceLine" id="cb182-2" title="2">withdraw value account <span class="ot">=</span> account <span class="op">-</span> value</a>
<a class="sourceLine" id="cb182-3" title="3"></a>
<a class="sourceLine" id="cb182-4" title="4"><span class="ot">eligible ::</span> (<span class="dt">Num</span> a,<span class="dt">Ord</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Bool</span></a>
<a class="sourceLine" id="cb182-5" title="5">eligible account <span class="ot">=</span></a>
<a class="sourceLine" id="cb182-6" title="6"> <span class="kw">let</span> account1 <span class="ot">=</span> deposit <span class="dv">100</span> account <span class="kw">in</span></a>
<a class="sourceLine" id="cb182-7" title="7"> <span class="kw">if</span> (account1 <span class="op">&lt;</span> <span class="dv">0</span>)</a>
<a class="sourceLine" id="cb182-8" title="8"> <span class="kw">then</span> <span class="dt">False</span></a>
<a class="sourceLine" id="cb182-9" title="9"> <span class="kw">else</span></a>
<a class="sourceLine" id="cb182-10" title="10"> <span class="kw">let</span> account2 <span class="ot">=</span> withdraw <span class="dv">200</span> account1 <span class="kw">in</span></a>
<a class="sourceLine" id="cb182-11" title="11"> <span class="kw">if</span> (account2 <span class="op">&lt;</span> <span class="dv">0</span>)</a>
<a class="sourceLine" id="cb182-12" title="12"> <span class="kw">then</span> <span class="dt">False</span></a>
<a class="sourceLine" id="cb182-13" title="13"> <span class="kw">else</span></a>
<a class="sourceLine" id="cb182-14" title="14"> <span class="kw">let</span> account3 <span class="ot">=</span> deposit <span class="dv">100</span> account2 <span class="kw">in</span></a>
<a class="sourceLine" id="cb182-15" title="15"> <span class="kw">if</span> (account3 <span class="op">&lt;</span> <span class="dv">0</span>)</a>
<a class="sourceLine" id="cb182-16" title="16"> <span class="kw">then</span> <span class="dt">False</span></a>
<a class="sourceLine" id="cb182-17" title="17"> <span class="kw">else</span></a>
<a class="sourceLine" id="cb182-18" title="18"> <span class="kw">let</span> account4 <span class="ot">=</span> withdraw <span class="dv">300</span> account3 <span class="kw">in</span></a>
<a class="sourceLine" id="cb182-19" title="19"> <span class="kw">if</span> (account4 <span class="op">&lt;</span> <span class="dv">0</span>)</a>
<a class="sourceLine" id="cb182-20" title="20"> <span class="kw">then</span> <span class="dt">False</span></a>
<a class="sourceLine" id="cb182-21" title="21"> <span class="kw">else</span></a>
<a class="sourceLine" id="cb182-22" title="22"> <span class="kw">let</span> account5 <span class="ot">=</span> deposit <span class="dv">1000</span> account4 <span class="kw">in</span></a>
<a class="sourceLine" id="cb182-23" title="23"> <span class="kw">if</span> (account5 <span class="op">&lt;</span> <span class="dv">0</span>)</a>
<a class="sourceLine" id="cb182-24" title="24"> <span class="kw">then</span> <span class="dt">False</span></a>
<a class="sourceLine" id="cb182-25" title="25"> <span class="kw">else</span></a>
<a class="sourceLine" id="cb182-26" title="26"> <span class="dt">True</span></a>
<a class="sourceLine" id="cb182-27" title="27"></a>
<a class="sourceLine" id="cb182-28" title="28">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb182-29" title="29"> <span class="fu">print</span> <span class="op">$</span> eligible <span class="dv">300</span> <span class="co">-- True</span></a>
<a class="sourceLine" id="cb182-30" title="30"> <span class="fu">print</span> <span class="op">$</span> eligible <span class="dv">299</span> <span class="co">-- False</span></a></code></pre></div>
</div>
<p><a href="code/03_Hell/02_Monads/10_Monads.lhs" class="cut">03_Hell/02_Monads/<strong>10_Monads.lhs</strong> </a></p>
<hr />
<p><a href="code/03_Hell/02_Monads/11_Monads.lhs" class="cut">03_Hell/02_Monads/<strong>11_Monads.lhs</strong></a></p>
<p>Maintenant, améliorons cela en utilisant le fait que <code>Maybe</code> est une Monade.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb183"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb183-1" title="1"><span class="ot">deposit ::</span> (<span class="dt">Num</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</a>
<a class="sourceLine" id="cb183-2" title="2">deposit value account <span class="ot">=</span> <span class="dt">Just</span> (account <span class="op">+</span> value)</a>
<a class="sourceLine" id="cb183-3" title="3"></a>
<a class="sourceLine" id="cb183-4" title="4"><span class="ot">withdraw ::</span> (<span class="dt">Num</span> a,<span class="dt">Ord</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</a>
<a class="sourceLine" id="cb183-5" title="5">withdraw value account <span class="ot">=</span> <span class="kw">if</span> (account <span class="op">&lt;</span> value) </a>
<a class="sourceLine" id="cb183-6" title="6"> <span class="kw">then</span> <span class="dt">Nothing</span> </a>
<a class="sourceLine" id="cb183-7" title="7"> <span class="kw">else</span> <span class="dt">Just</span> (account <span class="op">-</span> value)</a>
<a class="sourceLine" id="cb183-8" title="8"></a>
<a class="sourceLine" id="cb183-9" title="9"><span class="ot">eligible ::</span> (<span class="dt">Num</span> a, <span class="dt">Ord</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Bool</span></a>
<a class="sourceLine" id="cb183-10" title="10">eligible account <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb183-11" title="11"> account1 <span class="ot">&lt;-</span> deposit <span class="dv">100</span> account </a>
<a class="sourceLine" id="cb183-12" title="12"> account2 <span class="ot">&lt;-</span> withdraw <span class="dv">200</span> account1 </a>
<a class="sourceLine" id="cb183-13" title="13"> account3 <span class="ot">&lt;-</span> deposit <span class="dv">100</span> account2 </a>
<a class="sourceLine" id="cb183-14" title="14"> account4 <span class="ot">&lt;-</span> withdraw <span class="dv">300</span> account3 </a>
<a class="sourceLine" id="cb183-15" title="15"> account5 <span class="ot">&lt;-</span> deposit <span class="dv">1000</span> account4</a>
<a class="sourceLine" id="cb183-16" title="16"> <span class="dt">Just</span> <span class="dt">True</span></a>
<a class="sourceLine" id="cb183-17" title="17"></a>
<a class="sourceLine" id="cb183-18" title="18">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb183-19" title="19"> <span class="fu">print</span> <span class="op">$</span> eligible <span class="dv">300</span> <span class="co">-- Just True</span></a>
<a class="sourceLine" id="cb183-20" title="20"> <span class="fu">print</span> <span class="op">$</span> eligible <span class="dv">299</span> <span class="co">-- Nothing</span></a></code></pre></div>
</div>
<p><a href="code/03_Hell/02_Monads/11_Monads.lhs" class="cut">03_Hell/02_Monads/<strong>11_Monads.lhs</strong> </a></p>
<hr />
<p><a href="code/03_Hell/02_Monads/12_Monads.lhs" class="cut">03_Hell/02_Monads/<strong>12_Monads.lhs</strong></a></p>
<p>Pas mauvais, mais nous pouvons faire encore mieux&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb184"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb184-1" title="1"><span class="ot">deposit ::</span> (<span class="dt">Num</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</a>
<a class="sourceLine" id="cb184-2" title="2">deposit value account <span class="ot">=</span> <span class="dt">Just</span> (account <span class="op">+</span> value)</a>
<a class="sourceLine" id="cb184-3" title="3"></a>
<a class="sourceLine" id="cb184-4" title="4"><span class="ot">withdraw ::</span> (<span class="dt">Num</span> a,<span class="dt">Ord</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</a>
<a class="sourceLine" id="cb184-5" title="5">withdraw value account <span class="ot">=</span> <span class="kw">if</span> (account <span class="op">&lt;</span> value) </a>
<a class="sourceLine" id="cb184-6" title="6"> <span class="kw">then</span> <span class="dt">Nothing</span> </a>
<a class="sourceLine" id="cb184-7" title="7"> <span class="kw">else</span> <span class="dt">Just</span> (account <span class="op">-</span> value)</a>
<a class="sourceLine" id="cb184-8" title="8"></a>
<a class="sourceLine" id="cb184-9" title="9"><span class="ot">eligible ::</span> (<span class="dt">Num</span> a, <span class="dt">Ord</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Bool</span></a>
<a class="sourceLine" id="cb184-10" title="10">eligible account <span class="ot">=</span></a>
<a class="sourceLine" id="cb184-11" title="11"> deposit <span class="dv">100</span> account <span class="op">&gt;&gt;=</span></a>
<a class="sourceLine" id="cb184-12" title="12"> withdraw <span class="dv">200</span> <span class="op">&gt;&gt;=</span></a>
<a class="sourceLine" id="cb184-13" title="13"> deposit <span class="dv">100</span> <span class="op">&gt;&gt;=</span></a>
<a class="sourceLine" id="cb184-14" title="14"> withdraw <span class="dv">300</span> <span class="op">&gt;&gt;=</span></a>
<a class="sourceLine" id="cb184-15" title="15"> deposit <span class="dv">1000</span> <span class="op">&gt;&gt;</span></a>
<a class="sourceLine" id="cb184-16" title="16"> <span class="fu">return</span> <span class="dt">True</span></a>
<a class="sourceLine" id="cb184-17" title="17"></a>
<a class="sourceLine" id="cb184-18" title="18">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb184-19" title="19"> <span class="fu">print</span> <span class="op">$</span> eligible <span class="dv">300</span> <span class="co">-- Just True</span></a>
<a class="sourceLine" id="cb184-20" title="20"> <span class="fu">print</span> <span class="op">$</span> eligible <span class="dv">299</span> <span class="co">-- Nothing</span></a></code></pre></div>
</div>
<p>Nous avons prouvé que les monades sont un bon moyen de rendre notre code plus élégant. Remarquez que cette idée dorganisation de code, en particulier pour <code>Maybe</code>, peut être utilisée dans la plupart des langages impératifs. En fait, cest le type de construction que nous faisons naturellement.</p>
<blockquote>
<p>Une remarque importante&nbsp;:</p>
<p>Le premier élement de la séquence qui sera évalué comme <code>Nothing</code> stoppera lévaluation. Cela signifie que vous nexécutez pas toutes les lignes. Cela découle du caractère paresseux de Haskell.</p>
</blockquote>
<p>Vous pourriez aussi revoir ces exemples avec la définition de <code>(&gt;&gt;=)</code> pour <code>Maybe</code> en tête&nbsp;:</p>
<div class="sourceCode" id="cb185"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb185-1" title="1"><span class="kw">instance</span> <span class="dt">Monad</span> <span class="dt">Maybe</span> <span class="kw">where</span></a>
<a class="sourceLine" id="cb185-2" title="2"><span class="ot"> (&gt;&gt;=) ::</span> <span class="dt">Maybe</span> a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> b) <span class="ot">-&gt;</span> <span class="dt">Maybe</span> b</a>
<a class="sourceLine" id="cb185-3" title="3"> <span class="dt">Nothing</span> <span class="op">&gt;&gt;=</span> _ <span class="ot">=</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb185-4" title="4"> (<span class="dt">Just</span> x) <span class="op">&gt;&gt;=</span> f <span class="ot">=</span> f x</a>
<a class="sourceLine" id="cb185-5" title="5"></a>
<a class="sourceLine" id="cb185-6" title="6"> <span class="fu">return</span> x <span class="ot">=</span> <span class="dt">Just</span> x</a></code></pre></div>
<p>La monade <code>Maybe</code> a prouvé par un simple exemple quelle est utile. Nous avons vu lutilité de la monade <code>IO</code>. Mais maintenant, voici un exemple encore plus cool : les listes.</p>
<p><a href="code/03_Hell/02_Monads/12_Monads.lhs" class="cut">03_Hell/02_Monads/<strong>12_Monads.lhs</strong> </a></p>
<hr />
<p><a href="code/03_Hell/02_Monads/13_Monads.lhs" class="cut">03_Hell/02_Monads/<strong>13_Monads.lhs</strong></a></p>
<h4 id="the-list-monad">
La monade List
</h4>
<div>
<img src="../../../../Scratch/img/blog/Haskell-the-Hard-Way/golconde.jpg" alt="Golconde de Magritte" />
</div>
<p>La monade <code>List</code> nous aide à simuler des calculs non-déterministes. Cest parti&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb186"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb186-1" title="1"><span class="kw">import</span> <span class="dt">Control.Monad</span> (guard)</a>
<a class="sourceLine" id="cb186-2" title="2"></a>
<a class="sourceLine" id="cb186-3" title="3">allCases <span class="ot">=</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</a>
<a class="sourceLine" id="cb186-4" title="4"></a>
<a class="sourceLine" id="cb186-5" title="5"><span class="ot">resolve ::</span> [(<span class="dt">Int</span>,<span class="dt">Int</span>,<span class="dt">Int</span>)]</a>
<a class="sourceLine" id="cb186-6" title="6">resolve <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb186-7" title="7"> x <span class="ot">&lt;-</span> allCases</a>
<a class="sourceLine" id="cb186-8" title="8"> y <span class="ot">&lt;-</span> allCases</a>
<a class="sourceLine" id="cb186-9" title="9"> z <span class="ot">&lt;-</span> allCases</a>
<a class="sourceLine" id="cb186-10" title="10"> guard <span class="op">$</span> <span class="dv">4</span><span class="op">*</span>x <span class="op">+</span> <span class="dv">2</span><span class="op">*</span>y <span class="op">&lt;</span> z</a>
<a class="sourceLine" id="cb186-11" title="11"> <span class="fu">return</span> (x,y,z)</a>
<a class="sourceLine" id="cb186-12" title="12"></a>
<a class="sourceLine" id="cb186-13" title="13">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb186-14" title="14"> <span class="fu">print</span> resolve</a></code></pre></div>
</div>
<p>Ma. GIQUE.&nbsp;:</p>
<pre><code>[(1,1,7),(1,1,8),(1,1,9),(1,1,10),(1,2,9),(1,2,10)]</code></pre>
<p>Pour la monade <code>List</code>, il y a aussi un sucre syntaxique&nbsp;:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb188"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb188-1" title="1"> <span class="fu">print</span> <span class="op">$</span> [ (x,y,z) <span class="op">|</span> x <span class="ot">&lt;-</span> allCases,</a>
<a class="sourceLine" id="cb188-2" title="2"> y <span class="ot">&lt;-</span> allCases,</a>
<a class="sourceLine" id="cb188-3" title="3"> z <span class="ot">&lt;-</span> allCases,</a>
<a class="sourceLine" id="cb188-4" title="4"> <span class="dv">4</span><span class="op">*</span>x <span class="op">+</span> <span class="dv">2</span><span class="op">*</span>y <span class="op">&lt;</span> z ]</a></code></pre></div>
</div>
<p>Je ne listerai pas toutes les monades, car il y en a beaucoup. Utiliser les monades simplifie la manipulations de plusieurs notions dans les langages purs. Les monades sont très utiles, en particulier pour&nbsp;:</p>
<ul>
<li>LE/S (IO),</li>
<li>les calculs non-déterministes,</li>
<li>générer des nombres pseudo-aléatoires,</li>
<li>garder un état de configuration,</li>
<li>écrire un état,</li>
<li></li>
</ul>
<p>Si vous mavez suivi jusquici, alors vous avez terminé ! Vous connaissez les monades<a href="#fn6" class="footnote-ref" id="fnref6"><sup>6</sup></a> !</p>
<p><a href="code/03_Hell/02_Monads/13_Monads.lhs" class="cut">03_Hell/02_Monads/<strong>13_Monads.lhs</strong> </a></p>
<h2 id="appendix">
Appendice
</h2>
<p>Cette section nest pas vraiment sur lapprentissage dHaskell. Elle est ici pour discuter de quelques détails.</p>
<hr />
<p><a href="code/04_Appendice/01_More_on_infinite_trees/10_Infinite_Trees.lhs" class="cut">04_Appendice/01_More_on_infinite_trees/<strong>10_Infinite_Trees.lhs</strong></a></p>
<h3 id="more-on-infinite-tree">
Revenons sur les arbres infinis
</h3>
<p>Dans la section sur <a href="#infinite-structures">les structures infinies</a> nous avons vu quelques constructions simples. Malheureusement, nous avons enlevé deux propriétés de notre arbre:</p>
<ol type="1">
<li>Pas de valeurs identiques</li>
<li>Arbre bien ordonné</li>
</ol>
<p>Dans cette section nous allons tenter de garder la première propriété. Concernant la seconde, nous ne devons pas nous en préoccuper ici mais nous discuterons de comment la garder le plus possible.</p>
<div style="display:none">
<p>This code is mostly the same as the one in the <a href="#trees">tree section</a>.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb189"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb189-1" title="1"><span class="kw">import</span> <span class="dt">Data.List</span></a>
<a class="sourceLine" id="cb189-2" title="2"><span class="kw">data</span> <span class="dt">BinTree</span> a <span class="ot">=</span> <span class="dt">Empty</span> </a>
<a class="sourceLine" id="cb189-3" title="3"> <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">BinTree</span> a) (<span class="dt">BinTree</span> a) </a>
<a class="sourceLine" id="cb189-4" title="4"> <span class="kw">deriving</span> (<span class="dt">Eq</span>,<span class="dt">Ord</span>)</a>
<a class="sourceLine" id="cb189-5" title="5"></a>
<a class="sourceLine" id="cb189-6" title="6"><span class="co">-- declare BinTree a to be an instance of Show</span></a>
<a class="sourceLine" id="cb189-7" title="7"><span class="kw">instance</span> (<span class="dt">Show</span> a) <span class="ot">=&gt;</span> <span class="dt">Show</span> (<span class="dt">BinTree</span> a) <span class="kw">where</span></a>
<a class="sourceLine" id="cb189-8" title="8"> <span class="co">-- will start by a '&lt;' before the root</span></a>
<a class="sourceLine" id="cb189-9" title="9"> <span class="co">-- and put a : a begining of line</span></a>
<a class="sourceLine" id="cb189-10" title="10"> <span class="fu">show</span> t <span class="ot">=</span> <span class="st">&quot;&lt; &quot;</span> <span class="op">++</span> replace <span class="ch">'\n'</span> <span class="st">&quot;\n: &quot;</span> (treeshow <span class="st">&quot;&quot;</span> t)</a>
<a class="sourceLine" id="cb189-11" title="11"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb189-12" title="12"> treeshow pref <span class="dt">Empty</span> <span class="ot">=</span> <span class="st">&quot;&quot;</span></a>
<a class="sourceLine" id="cb189-13" title="13"> treeshow pref (<span class="dt">Node</span> x <span class="dt">Empty</span> <span class="dt">Empty</span>) <span class="ot">=</span> </a>
<a class="sourceLine" id="cb189-14" title="14"> (pshow pref x)</a>
<a class="sourceLine" id="cb189-15" title="15"></a>
<a class="sourceLine" id="cb189-16" title="16"> treeshow pref (<span class="dt">Node</span> x left <span class="dt">Empty</span>) <span class="ot">=</span> </a>
<a class="sourceLine" id="cb189-17" title="17"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb189-18" title="18"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> left)</a>
<a class="sourceLine" id="cb189-19" title="19"></a>
<a class="sourceLine" id="cb189-20" title="20"> treeshow pref (<span class="dt">Node</span> x <span class="dt">Empty</span> right) <span class="ot">=</span> </a>
<a class="sourceLine" id="cb189-21" title="21"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb189-22" title="22"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> right)</a>
<a class="sourceLine" id="cb189-23" title="23"></a>
<a class="sourceLine" id="cb189-24" title="24"> treeshow pref (<span class="dt">Node</span> x left right) <span class="ot">=</span> </a>
<a class="sourceLine" id="cb189-25" title="25"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb189-26" title="26"> (showSon pref <span class="st">&quot;|--&quot;</span> <span class="st">&quot;| &quot;</span> left) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb189-27" title="27"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> right)</a>
<a class="sourceLine" id="cb189-28" title="28"></a>
<a class="sourceLine" id="cb189-29" title="29"> <span class="co">-- show a tree using some prefixes to make it nice</span></a>
<a class="sourceLine" id="cb189-30" title="30"> showSon pref before next t <span class="ot">=</span> </a>
<a class="sourceLine" id="cb189-31" title="31"> pref <span class="op">++</span> before <span class="op">++</span> treeshow (pref <span class="op">++</span> next) t</a>
<a class="sourceLine" id="cb189-32" title="32"></a>
<a class="sourceLine" id="cb189-33" title="33"> <span class="co">-- pshow replace &quot;\n&quot; by &quot;\n&quot;++pref</span></a>
<a class="sourceLine" id="cb189-34" title="34"> pshow pref x <span class="ot">=</span> replace <span class="ch">'\n'</span> (<span class="st">&quot;\n&quot;</span><span class="op">++</span>pref) (<span class="fu">show</span> x)</a>
<a class="sourceLine" id="cb189-35" title="35"></a>
<a class="sourceLine" id="cb189-36" title="36"> <span class="co">-- replace on char by another string</span></a>
<a class="sourceLine" id="cb189-37" title="37"> replace c new string <span class="ot">=</span></a>
<a class="sourceLine" id="cb189-38" title="38"> <span class="fu">concatMap</span> (change c new) string</a>
<a class="sourceLine" id="cb189-39" title="39"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb189-40" title="40"> change c new x </a>
<a class="sourceLine" id="cb189-41" title="41"> <span class="op">|</span> x <span class="op">==</span> c <span class="ot">=</span> new</a>
<a class="sourceLine" id="cb189-42" title="42"> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> x<span class="op">:</span>[] <span class="co">-- &quot;x&quot;</span></a></code></pre></div>
</div>
</div>
<p>Notre première étape est de créer une liste de nombres pseudo-aléatoires:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb190"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb190-1" title="1">shuffle <span class="ot">=</span> <span class="fu">map</span> (\x <span class="ot">-&gt;</span> (x<span class="op">*</span><span class="dv">3123</span>) <span class="ot">`mod`</span> <span class="dv">4331</span>) [<span class="dv">1</span><span class="op">..</span>]</a></code></pre></div>
</div>
<p>Pour mémoire, voici la définition de <code>treeFromList</code></p>
<div class="codehighlight">
<div class="sourceCode" id="cb191"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb191-1" title="1"><span class="ot">treeFromList ::</span> (<span class="dt">Ord</span> a) <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">BinTree</span> a</a>
<a class="sourceLine" id="cb191-2" title="2">treeFromList [] <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb191-3" title="3">treeFromList (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Node</span> x (treeFromList (<span class="fu">filter</span> (<span class="op">&lt;</span>x) xs))</a>
<a class="sourceLine" id="cb191-4" title="4"> (treeFromList (<span class="fu">filter</span> (<span class="op">&gt;</span>x) xs))</a></code></pre></div>
</div>
<p>et <code>treeTakeDepth</code>:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb192"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb192-1" title="1">treeTakeDepth _ <span class="dt">Empty</span> <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb192-2" title="2">treeTakeDepth <span class="dv">0</span> _ <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb192-3" title="3">treeTakeDepth n (<span class="dt">Node</span> x left right) <span class="ot">=</span> <span class="kw">let</span></a>
<a class="sourceLine" id="cb192-4" title="4"> nl <span class="ot">=</span> treeTakeDepth (n<span class="op">-</span><span class="dv">1</span>) left</a>
<a class="sourceLine" id="cb192-5" title="5"> nr <span class="ot">=</span> treeTakeDepth (n<span class="op">-</span><span class="dv">1</span>) right</a>
<a class="sourceLine" id="cb192-6" title="6"> <span class="kw">in</span></a>
<a class="sourceLine" id="cb192-7" title="7"> <span class="dt">Node</span> x nl nr</a></code></pre></div>
</div>
<p>Voyez le résultats de:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb193"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb193-1" title="1">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb193-2" title="2"> <span class="fu">putStrLn</span> <span class="st">&quot;take 10 shuffle&quot;</span></a>
<a class="sourceLine" id="cb193-3" title="3"> <span class="fu">print</span> <span class="op">$</span> <span class="fu">take</span> <span class="dv">10</span> shuffle</a>
<a class="sourceLine" id="cb193-4" title="4"> <span class="fu">putStrLn</span> <span class="st">&quot;\ntreeTakeDepth 4 (treeFromList shuffle)&quot;</span></a>
<a class="sourceLine" id="cb193-5" title="5"> <span class="fu">print</span> <span class="op">$</span> treeTakeDepth <span class="dv">4</span> (treeFromList shuffle)</a></code></pre></div>
</div>
<pre><code>% runghc 02_Hard_Part/41_Infinites_Structures.lhs
take 10 shuffle
[3123,1915,707,3830,2622,1414,206,3329,2121,913]
treeTakeDepth 4 (treeFromList shuffle)
&lt; 3123
: |--1915
: | |--707
: | | |--206
: | | `--1414
: | `--2622
: | |--2121
: | `--2828
: `--3830
: |--3329
: | |--3240
: | `--3535
: `--4036
: |--3947
: `--4242</code></pre>
<p>Le code fonctionne! Attention cependant, cela marchere seulement si vous avez toujours quelque chose à mettre dans une branche.</p>
<p>Par exemple</p>
<div class="sourceCode" id="cb195"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb195-1" title="1">treeTakeDepth <span class="dv">4</span> (treeFromList [<span class="dv">1</span><span class="op">..</span>]) </a></code></pre></div>
<p>tournera en boucle pour toujours. Simplement parce que le code essayera daccéder à première valeur de <code>filter (&lt;1) [2..]</code>. Mais <code>filter</code> nest pas assez intelligent pour comprendre que le résultat est une liste vide.</p>
<p>Toutefois, cela reste un exemple sympa de ce quun programme non-stricit a à offrir.</p>
<p>Laissé pour exercice au lecteur:</p>
<ul>
<li>Prouver lexistence dun nombre <code>n</code> tel que <code>treeTakeDepth n (treeFromList shuffle)</code> provoquera une boucle infinie.</li>
<li>Trouver une borne supérieur <code>n</code>.</li>
<li>Prouver quil n(y a pas de liste <code>shuffle</code> qui termine le programme pour nimporte quelle profondeur.</li>
</ul>
<p><a href="code/04_Appendice/01_More_on_infinite_trees/10_Infinite_Trees.lhs" class="cut">04_Appendice/01_More_on_infinite_trees/<strong>10_Infinite_Trees.lhs</strong> </a></p>
<hr />
<p><a href="code/04_Appendice/01_More_on_infinite_trees/11_Infinite_Trees.lhs" class="cut">04_Appendice/01_More_on_infinite_trees/<strong>11_Infinite_Trees.lhs</strong></a></p>
<div style="display:none">
<p>This code is mostly the same as the preceding one.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb196"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb196-1" title="1"><span class="kw">import</span> <span class="dt">Debug.Trace</span> (trace)</a>
<a class="sourceLine" id="cb196-2" title="2"><span class="kw">import</span> <span class="dt">Data.List</span></a>
<a class="sourceLine" id="cb196-3" title="3"><span class="kw">data</span> <span class="dt">BinTree</span> a <span class="ot">=</span> <span class="dt">Empty</span> </a>
<a class="sourceLine" id="cb196-4" title="4"> <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">BinTree</span> a) (<span class="dt">BinTree</span> a) </a>
<a class="sourceLine" id="cb196-5" title="5"> <span class="kw">deriving</span> (<span class="dt">Eq</span>,<span class="dt">Ord</span>)</a></code></pre></div>
</div>
<div class="codehighlight">
<div class="sourceCode" id="cb197"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb197-1" title="1"><span class="co">-- declare BinTree a to be an instance of Show</span></a>
<a class="sourceLine" id="cb197-2" title="2"><span class="kw">instance</span> (<span class="dt">Show</span> a) <span class="ot">=&gt;</span> <span class="dt">Show</span> (<span class="dt">BinTree</span> a) <span class="kw">where</span></a>
<a class="sourceLine" id="cb197-3" title="3"> <span class="co">-- will start by a '&lt;' before the root</span></a>
<a class="sourceLine" id="cb197-4" title="4"> <span class="co">-- and put a : a begining of line</span></a>
<a class="sourceLine" id="cb197-5" title="5"> <span class="fu">show</span> t <span class="ot">=</span> <span class="st">&quot;&lt; &quot;</span> <span class="op">++</span> replace <span class="ch">'\n'</span> <span class="st">&quot;\n: &quot;</span> (treeshow <span class="st">&quot;&quot;</span> t)</a>
<a class="sourceLine" id="cb197-6" title="6"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb197-7" title="7"> treeshow pref <span class="dt">Empty</span> <span class="ot">=</span> <span class="st">&quot;&quot;</span></a>
<a class="sourceLine" id="cb197-8" title="8"> treeshow pref (<span class="dt">Node</span> x <span class="dt">Empty</span> <span class="dt">Empty</span>) <span class="ot">=</span> </a>
<a class="sourceLine" id="cb197-9" title="9"> (pshow pref x)</a>
<a class="sourceLine" id="cb197-10" title="10"></a>
<a class="sourceLine" id="cb197-11" title="11"> treeshow pref (<span class="dt">Node</span> x left <span class="dt">Empty</span>) <span class="ot">=</span> </a>
<a class="sourceLine" id="cb197-12" title="12"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb197-13" title="13"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> left)</a>
<a class="sourceLine" id="cb197-14" title="14"></a>
<a class="sourceLine" id="cb197-15" title="15"> treeshow pref (<span class="dt">Node</span> x <span class="dt">Empty</span> right) <span class="ot">=</span> </a>
<a class="sourceLine" id="cb197-16" title="16"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb197-17" title="17"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> right)</a>
<a class="sourceLine" id="cb197-18" title="18"></a>
<a class="sourceLine" id="cb197-19" title="19"> treeshow pref (<span class="dt">Node</span> x left right) <span class="ot">=</span> </a>
<a class="sourceLine" id="cb197-20" title="20"> (pshow pref x) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb197-21" title="21"> (showSon pref <span class="st">&quot;|--&quot;</span> <span class="st">&quot;| &quot;</span> left) <span class="op">++</span> <span class="st">&quot;\n&quot;</span> <span class="op">++</span></a>
<a class="sourceLine" id="cb197-22" title="22"> (showSon pref <span class="st">&quot;`--&quot;</span> <span class="st">&quot; &quot;</span> right)</a>
<a class="sourceLine" id="cb197-23" title="23"></a>
<a class="sourceLine" id="cb197-24" title="24"> <span class="co">-- show a tree using some prefixes to make it nice</span></a>
<a class="sourceLine" id="cb197-25" title="25"> showSon pref before next t <span class="ot">=</span> </a>
<a class="sourceLine" id="cb197-26" title="26"> pref <span class="op">++</span> before <span class="op">++</span> treeshow (pref <span class="op">++</span> next) t</a>
<a class="sourceLine" id="cb197-27" title="27"></a>
<a class="sourceLine" id="cb197-28" title="28"> <span class="co">-- pshow replace &quot;\n&quot; by &quot;\n&quot;++pref</span></a>
<a class="sourceLine" id="cb197-29" title="29"> pshow pref x <span class="ot">=</span> replace <span class="ch">'\n'</span> (<span class="st">&quot;\n&quot;</span><span class="op">++</span>pref) (<span class="st">&quot; &quot;</span> <span class="op">++</span> <span class="fu">show</span> x)</a>
<a class="sourceLine" id="cb197-30" title="30"></a>
<a class="sourceLine" id="cb197-31" title="31"> <span class="co">-- replace on char by another string</span></a>
<a class="sourceLine" id="cb197-32" title="32"> replace c new string <span class="ot">=</span></a>
<a class="sourceLine" id="cb197-33" title="33"> <span class="fu">concatMap</span> (change c new) string</a>
<a class="sourceLine" id="cb197-34" title="34"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb197-35" title="35"> change c new x </a>
<a class="sourceLine" id="cb197-36" title="36"> <span class="op">|</span> x <span class="op">==</span> c <span class="ot">=</span> new</a>
<a class="sourceLine" id="cb197-37" title="37"> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> x<span class="op">:</span>[] <span class="co">-- &quot;x&quot;</span></a>
<a class="sourceLine" id="cb197-38" title="38"></a>
<a class="sourceLine" id="cb197-39" title="39">treeTakeDepth _ <span class="dt">Empty</span> <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb197-40" title="40">treeTakeDepth <span class="dv">0</span> _ <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb197-41" title="41">treeTakeDepth n (<span class="dt">Node</span> x left right) <span class="ot">=</span> <span class="kw">let</span></a>
<a class="sourceLine" id="cb197-42" title="42"> nl <span class="ot">=</span> treeTakeDepth (n<span class="op">-</span><span class="dv">1</span>) left</a>
<a class="sourceLine" id="cb197-43" title="43"> nr <span class="ot">=</span> treeTakeDepth (n<span class="op">-</span><span class="dv">1</span>) right</a>
<a class="sourceLine" id="cb197-44" title="44"> <span class="kw">in</span></a>
<a class="sourceLine" id="cb197-45" title="45"> <span class="dt">Node</span> x nl nr</a></code></pre></div>
</div>
</div>
<p>Pour résoudre ces problèmes nous allons modifier légèrement nos fonctions <code>treeFromList</code> et <code>shuffle</code>.</p>
<p>Un premier problème est le manque de nombres différents dans notre immlémentation de <code>shuffle</code>. Nous avons généré seulement <code>4331</code> nombres différents. Pour résoudre cela nous allons faire un meilleure fonction <code>shuffle</code>.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb198"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb198-1" title="1">shuffle <span class="ot">=</span> <span class="fu">map</span> rand [<span class="dv">1</span><span class="op">..</span>]</a>
<a class="sourceLine" id="cb198-2" title="2"> <span class="kw">where</span> </a>
<a class="sourceLine" id="cb198-3" title="3"> rand x <span class="ot">=</span> ((p x) <span class="ot">`mod`</span> (x<span class="op">+</span>c)) <span class="op">-</span> ((x<span class="op">+</span>c) <span class="ot">`div`</span> <span class="dv">2</span>)</a>
<a class="sourceLine" id="cb198-4" title="4"> p x <span class="ot">=</span> m<span class="op">*</span>x<span class="op">^</span><span class="dv">2</span> <span class="op">+</span> n<span class="op">*</span>x <span class="op">+</span> o <span class="co">-- some polynome</span></a>
<a class="sourceLine" id="cb198-5" title="5"> m <span class="ot">=</span> <span class="dv">3123</span> </a>
<a class="sourceLine" id="cb198-6" title="6"> n <span class="ot">=</span> <span class="dv">31</span></a>
<a class="sourceLine" id="cb198-7" title="7"> o <span class="ot">=</span> <span class="dv">7641</span></a>
<a class="sourceLine" id="cb198-8" title="8"> c <span class="ot">=</span> <span class="dv">1237</span></a></code></pre></div>
</div>
<p>Cette fonction à la propriété de ne pas avoir de bornes supérieure ou inférieure. Mais avoir une meilleure list <code>shuffle</code> nest pas assez pour entrer dans une boucle infinie.</p>
<p>Généralement, nous ne pouvons pas décider que <code>filter (&lt;x) xs</code> est vide. Donc pour résoudre le problème, je vais autoriser quelques erreurs dans la création de notre arbre binaire. Cette nouvelle version du code peut créer des arbres binaires qui nont pas à suivre les propriétés suivantes pour quelque uns de leurs noeuds:</p>
<blockquote>
<p>Tous les élements de la branche de gauche doit être strictement inférieur au la valeur racine.</p>
</blockquote>
<p>Remarquez que cela donnera <em>souvent</em> un arbre ordonné. En outre, avec cette construction, chaque noeud est unique dans larbre.</p>
<p>Voici notre nouvelle version de <code>treeFromList</code>. Nous avons simplement remplacé <code>filter</code> par <code>safefilter</code>.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb199"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb199-1" title="1"><span class="ot">treeFromList ::</span> (<span class="dt">Ord</span> a, <span class="dt">Show</span> a) <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">BinTree</span> a</a>
<a class="sourceLine" id="cb199-2" title="2">treeFromList [] <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb199-3" title="3">treeFromList (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Node</span> x left right</a>
<a class="sourceLine" id="cb199-4" title="4"> <span class="kw">where</span> </a>
<a class="sourceLine" id="cb199-5" title="5"> left <span class="ot">=</span> treeFromList <span class="op">$</span> safefilter (<span class="op">&lt;</span>x) xs</a>
<a class="sourceLine" id="cb199-6" title="6"> right <span class="ot">=</span> treeFromList <span class="op">$</span> safefilter (<span class="op">&gt;</span>x) xs</a></code></pre></div>
</div>
<p>Cette nouvelle fonction <code>safefilter</code> est presque équivalente à <code>filter</code> mais nentre pas dans des boucles infinies si le résultat est une liste finie. Si elle ne peut pas trouver un élément pour lequel le test est vrai après 10000 étapes consécutives, alors elle considère que la recherche est finie.</p>
<div class="codehighlight">
<div class="sourceCode" id="cb200"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb200-1" title="1"><span class="ot">safefilter ::</span> (a <span class="ot">-&gt;</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [a]</a>
<a class="sourceLine" id="cb200-2" title="2">safefilter f l <span class="ot">=</span> safefilter' f l nbTry</a>
<a class="sourceLine" id="cb200-3" title="3"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb200-4" title="4"> nbTry <span class="ot">=</span> <span class="dv">10000</span></a>
<a class="sourceLine" id="cb200-5" title="5"> safefilter' _ _ <span class="dv">0</span> <span class="ot">=</span> []</a>
<a class="sourceLine" id="cb200-6" title="6"> safefilter' _ [] _ <span class="ot">=</span> []</a>
<a class="sourceLine" id="cb200-7" title="7"> safefilter' f (x<span class="op">:</span>xs) n <span class="ot">=</span> </a>
<a class="sourceLine" id="cb200-8" title="8"> <span class="kw">if</span> f x </a>
<a class="sourceLine" id="cb200-9" title="9"> <span class="kw">then</span> x <span class="op">:</span> safefilter' f xs nbTry </a>
<a class="sourceLine" id="cb200-10" title="10"> <span class="kw">else</span> safefilter' f xs (n<span class="op">-</span><span class="dv">1</span>) </a></code></pre></div>
</div>
<p>Maintenant faites tourner le programme et soyez heureux:</p>
<div class="codehighlight">
<div class="sourceCode" id="cb201"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb201-1" title="1">main <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb201-2" title="2"> <span class="fu">putStrLn</span> <span class="st">&quot;take 10 shuffle&quot;</span></a>
<a class="sourceLine" id="cb201-3" title="3"> <span class="fu">print</span> <span class="op">$</span> <span class="fu">take</span> <span class="dv">10</span> shuffle</a>
<a class="sourceLine" id="cb201-4" title="4"> <span class="fu">putStrLn</span> <span class="st">&quot;\ntreeTakeDepth 8 (treeFromList shuffle)&quot;</span></a>
<a class="sourceLine" id="cb201-5" title="5"> <span class="fu">print</span> <span class="op">$</span> treeTakeDepth <span class="dv">8</span> (treeFromList <span class="op">$</span> shuffle)</a></code></pre></div>
</div>
<p>Vous devriez réaliser que le temps nécessaire pour afficher chaque valeur est différent. Cest parce que Haskell calcule chaque valeur lorsquil en a besoin. Et dans ce cas, il est demandé de lafficher à lécran.</p>
<p>Vous pouvez même essayer de remplacer la profondeur de <code>8</code> par <code>100</code>. Cela marchera sans tuer votre RAM! La gestion de la mémoire est faite naturellement par Haskell.</p>
<p>Laissé comme exercices au lecteur:</p>
<ul>
<li>Même avec une grande valeur constante pour <code>deep</code> et <code>nbTry</code>, cela semble marcher correctement. Mais dans le pire des cas, cela peut devenir exponentiel. Créez la pire liste à donner comme paramètre à <code>treeFromList</code>. <em>indice</em>: pensez à (<code>[0,-1,-1,....,-1,1,-1,...,-1,1,...]</code>).</li>
<li>Jai commencé à implémenter <code>safefilter</code> comme ceci:
<pre>
safefilter' f l = if filter f (take 10000 l) == []
then []
else filter f l
</pre>
Expliquer pourquoi cela ne fonctionne pas et peut entrer dans une boucle infinie.</li>
<li>Supposez que <code>shuffle</code> est une liste de nombre réellement aléatoires avec de plus en plus de bornes. Si vous étudiez un peu cette structure, vous découvrirez quelle a toutes les chances dêtre finie. En utilisant le code suivant (supposez que nous pouvons utliser <code>safefilter'</code> directement comme si cela nétait pas dans le <code>where</code> de <code>safefilter</code>. trouvez une définition de <code>f</code> telle que, avec une probabilité de <code>1</code>, <code>treeFromList' shuffle</code> est infinie?. Et prouvez-le. Avertissement, ce nest quune conjecture.</li>
</ul>
<div class="sourceCode" id="cb202"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb202-1" title="1">treeFromList' [] n <span class="ot">=</span> <span class="dt">Empty</span></a>
<a class="sourceLine" id="cb202-2" title="2">treeFromList' (x<span class="op">:</span>xs) n <span class="ot">=</span> <span class="dt">Node</span> x left right</a>
<a class="sourceLine" id="cb202-3" title="3"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb202-4" title="4"> left <span class="ot">=</span> treeFromList' (safefilter' (<span class="op">&lt;</span>x) xs (f n)</a>
<a class="sourceLine" id="cb202-5" title="5"> right <span class="ot">=</span> treeFromList' (safefilter' (<span class="op">&gt;</span>x) xs (f n)</a>
<a class="sourceLine" id="cb202-6" title="6"> f <span class="ot">=</span> <span class="op">???</span></a></code></pre></div>
<p><a href="code/04_Appendice/01_More_on_infinite_trees/11_Infinite_Trees.lhs" class="cut">04_Appendice/01_More_on_infinite_trees/<strong>11_Infinite_Trees.lhs</strong> </a></p>
<h2 id="remerciements">Remerciements</h2>
<p>Merci à <a href="http://reddit.com/r/haskell"><code>/r/haskell</code></a> et <a href="http://reddit.com/r/programming"><code>/r/programming</code></a>. Vos commentaires étaient plus que bienvenus.</p>
<p>Particulièrement, je voudrais remercier mille fois <a href="https://github.com/Emm">Emm</a> pour le temps quil a consacré à corriger mon anglais. Merci beaucoup.</p>
<section class="footnotes">
<hr />
<ol>
<li id="fn1"><p>Même si tous les langages récents essayent de les cacher, ils restent présents.<a href="#fnref1" class="footnote-back"></a></p></li>
<li id="fn2"><p>Je sais que je triche. Mais je parlerais de la non-rigueur plus tard. <!-- IL FAUDRA TROUVER UNE AUTRE TRADUCTION POUR NON-STRICTNESS --><a href="#fnref2" class="footnote-back"></a></p></li>
<li id="fn3"><p>Qui est elle-même très similaire à la fonction <code>eval</code> de javascript, appliquée sur une chaîne contenant du code au format JSON.<a href="#fnref3" class="footnote-back"></a></p></li>
<li id="fn4"><p>Il y a quelques exceptions <em>peu sûres</em> à cette règle. Mais vous ne devriez pas en voir en application réelle, sauf pour le <em>debugging</em>.<a href="#fnref4" class="footnote-back"></a></p></li>
<li id="fn5"><p>Pour les curieux, le vrai type est <code>data IO a = IO {unIO :: State# RealWorld -&gt; (# State# RealWorld, a #)}</code>. Tous les <code>#</code> ont rapport avec loptimisation et jai échangé quelques champs dans mon exemple. Mais cest lidée de base.<a href="#fnref5" class="footnote-back"></a></p></li>
<li id="fn6"><p>Vous aurez quand même besoin de pratiquer un peu pour vous habituer à elles et pour comprendre quand les utiliser et créer les vôtres. Mais vous avez déjà fait un grand pas dans cette direction.<a href="#fnref6" class="footnote-back"></a></p></li>
</ol>
</section>
</div>
<div id="afterarticle">
<div id="social">
<a href="/rss.xml" target="_blank" rel="noopener noreferrer nofollow" class="social">RSS</a>
·
<a href="https://twitter.com/home?status=http%3A%2F%2Fyannesposito.com/Scratch/fr/blog/Haskell-the-Hard-Way/%20via%20@yogsototh" target="_blank" rel="noopener noreferrer nofollow" class="social">Tweet</a>
·
<a href="http://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fyannesposito.com/Scratch/fr/blog/Haskell-the-Hard-Way/" target="_blank" rel="noopener noreferrer nofollow" class="social">FB</a>
<br />
<a class="message" href="../../../../Scratch/fr/blog/Social-link-the-right-way/">Ces liens sociaux préservent votre vie privée</a>
</div>
<div id="navigation">
<a href="../../../../">Accueil</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/fr/blog">Blog</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/fr/softwares">Logiciels</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/fr/about">Auteur</a>
</div>
<div id="totop"><a href="#header">↑ Top ↑</a></div>
<div id="bottom">
<div>
Published on 2012-02-08
</div>
<div>
<a href="https://twitter.com/yogsototh">Follow @yogsototh</a>
</div>
<div>
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US">Yann Esposito©</a>
</div>
<div>
Done with
<a href="http://www.vim.org" target="_blank" rel="noopener noreferrer nofollow"><strike>Vim</strike></a>
<a href="http://spacemacs.org" target="_blank" rel="noopener noreferrer nofollow">spacemacs</a>
<span class="pala">&amp;</span>
<a href="http://nanoc.ws" target="_blank" rel="noopener noreferrer nofollow"><strike>nanoc</strike></a>
<a href="http://jaspervdj.be/hakyll" target="_blank" rel="noopener noreferrer nofollow">Hakyll</a>
</div>
<hr />
<div style="max-width: 100%">
<a href="https://cardanohub.org">
<img src="../../../../Scratch/img/ada-logo.png" class="simple" style="height: 16px;
border-radius: 50%;
vertical-align:middle;
display:inline-block;" />
ADA:
</a>
<code style="display:inline-block;
word-wrap:break-word;
text-align: left;
vertical-align: top;
max-width: 85%;">
DdzFFzCqrhtAvdkmATx5Fm8NPJViDy85ZBw13p4XcNzVzvQg8e3vWLXq23JQWFxPEXK6Kvhaxxe7oJt4VMYHxpA2vtCFiP8fziohN6Yp
</code>
</div>
</div>
</div>
</div>
</div>
</body>
</html>