<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[dsferruzza]]></title><description><![CDATA[David Sferruzza's personal website.]]></description><link>http://github.com/dylang/node-rss</link><generator>GatsbyJS</generator><lastBuildDate>Mon, 28 Oct 2024 16:44:45 GMT</lastBuildDate><item><title><![CDATA[Talk : Introduction à la programmation fonctionnelle en Scala]]></title><description><![CDATA[<p>Le mardi 5 mars 2019 j'ai donné une présentation d'introduction à la programmation fonctionnelle au <a href="https://www.meetup.com/fr-FR/Scala-Nantes-User-Group-SNUG/" target="_blank" rel="nofollow noopener">Scala Nantes User Group</a>. Il s'agit d'une version légérement remasterisée de la présentation que j'avais donnée à <a href="https://scala.io/" target="_blank" rel="nofollow noopener">Scala.io</a> 2016 (les concepts n'ont pas beaucoup changé depuis 😜).</p>
<p>Voici la vidéo, enregistrée par <a href="https://twitter.com/jutanguy" target="_blank" rel="nofollow noopener">Julien Tanguy</a> (merci 😘) :</p>
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/3Ma08gaAIDs" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>Les slides sont disponibles ici : <a href="https://dsferruzza.github.io/conf-programmation-fonctionnelle-en-scala" target="_blank" rel="nofollow noopener">https://dsferruzza.github.io/conf-programmation-fonctionnelle-en-scala</a></p>]]></description><link>https://david.sferruzza.fr/blog/2019-03-18-talk-introduction-a-la-programmation-fonctionnelle-en-scala/</link><guid isPermaLink="false">https://david.sferruzza.fr/blog/2019-03-18-talk-introduction-a-la-programmation-fonctionnelle-en-scala/</guid><pubDate>Mon, 18 Mar 2019 14:45:00 GMT</pubDate></item><item><title><![CDATA[Un bon livre pour se lancer en Haskell]]></title><description><![CDATA[<p>Il y a une dizaine de mois j'ai été contacté par <strong>Julien Dehos</strong>, maître de conférences en informatique à l'Université du Littoral Côte d'Opale, pour être relecteur officiel de son futur livre sur Haskell et la programmation fonctionnelle.</p>
<p>Le livre est récemment sorti sous le titre :</p>
<blockquote>
<p><strong>La programmation fonctionnelle</strong></p>
<p>Introduction et applications en Haskell à l'usage de l'étudiant et du développeur</p>
</blockquote>
<p>Pour moi, ce livre a un positionnement intéressant parmi les autres livres qui parlent de Haskell :</p>
<ul>
<li>il est en <strong>français</strong></li>
<li>il n'est pas horriblement long (<strong>~250 pages</strong> ici)</li>
<li>il a un <strong>bon équilibre</strong> entre les aspects théoriques (historique, concepts) et pratiques (pas besoin d'attendre la moitié du livre pour écrire et exécuter du code, un "gros" exemple est développé dans 5 langages en plus de Haskell pour pouvoir comparer)</li>
<li>il a un prix raisonnable pour ce genre d'ouvrages (<strong>32 €</strong>)</li>
</ul>
<p>On cite souvent <a href="http://haskellbook.com/" target="_blank" rel="nofollow noopener">Haskell Programming From First Principles</a> comme une bonne ressource pour débuter. Mais il est en anglais. Et il fait 1000+ pages. Et il coûte 59$. Et il n'y a pas de version papier. C'est clairement un bon bouquin, mais il demande beaucoup plus d'investissement. Le livre de Julien permet d'y aller plus en douceur et je pense que c'est une vraie qualité pour les débutants !</p>
<p>Pour l'acheter ou jeter un œil au sommaire ou au 1<sup>er</sup> chapitre, rendez-vous sur <a href="https://www.editions-ellipses.fr/programmation-fonctionnelle-introduction-applications-haskell-lusage-letudiant-developpeur-p-13083.html" target="_blank" rel="nofollow noopener">le site de l'éditeur</a> !</p>
<p><img src="/img/la-programmation-fonctionnelle-introduction-et-applications-en-haskell-a-lusage-de-letudiant-et-du-developpeur.jpg" alt="La couverture du livre" title="La couverture du livre"></p>
<p><img src="/img/relecteur.jpg" alt="Ma bio dans le livre" title="Ma bio dans le livre"></p>]]></description><link>https://david.sferruzza.fr/blog/2019-03-03-un-bon-livre-pour-apprendre-la-programmation-fonctionnelle/</link><guid isPermaLink="false">https://david.sferruzza.fr/blog/2019-03-03-un-bon-livre-pour-apprendre-la-programmation-fonctionnelle/</guid><pubDate>Mon, 04 Mar 2019 10:33:05 GMT</pubDate></item><item><title><![CDATA[Gérer les erreurs avec l'aide du système de types de Scala !]]></title><description><![CDATA[<p>Le 22 avril dernier, j'ai eu la chance de donner une conférence de 45 minutes à <a href="https://devoxx.fr/" target="_blank" rel="nofollow noopener">DevoxxFR</a> :</p>
<blockquote>
<p><strong>Gérer les erreurs avec l'aide du système de types de Scala !</strong></p>
<p>Certaines fonctions de nos programmes peuvent échouer à calculer une valeur de retour. Plutôt que d'utiliser des exceptions, il est possible de tirer partie du système de types de Scala pour gérer les erreurs de manière plus fiable et lisible.</p>
<p>Nous verrons comment utiliser des ADT (Algebraic Data Type) comme <code class="language-text">Option</code>, <code class="language-text">Try</code> et <code class="language-text">Either</code>, ainsi que <code class="language-text">disjunction</code> et <code class="language-text">validation</code> de <a href="https://github.com/scalaz/scalaz" target="_blank" rel="nofollow noopener">Scalaz</a>. On regardera aussi la bibliothèque <a href="http://rapture.io/" target="_blank" rel="nofollow noopener">Rapture</a> et ses "modes" qui offrent la possibilité <em>à l'appelant</em> de choisir de quelle manière il veut encapsuler les éventuelles erreurs.</p>
<p>La gestion des erreurs est bien moins compliquée lorsque le compilateur peut nous aider !</p>
</blockquote>
<p>Voilà la vidéo et les slides :</p>
<ul>
<li>Slides : <a href="https://dsferruzza.github.io/conf-gestion-erreurs-en-scala/" target="_blank" rel="nofollow noopener">https://dsferruzza.github.io/conf-gestion-erreurs-en-scala/</a> (<a href="https://github.com/dsferruzza/conf-gestion-erreurs-en-scala" target="_blank" rel="nofollow noopener">dépôt GitHub</a>)</li>
<li>Vidéo : <a href="https://www.youtube.com/watch?v=TwJQKrZ23Vs" target="_blank" rel="nofollow noopener">https://www.youtube.com/watch?v=TwJQKrZ23Vs</a></li>
</ul>
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/TwJQKrZ23Vs?rel=0" frameborder="0" allowfullscreen></iframe>
<p>DevoxxFR 2016 c'était super, et j'espère revenir l'année prochaine !</p>
<p><em>Merci à <a href="http://blog.clement.delafargue.name/" target="_blank" rel="nofollow noopener">Clément Delafargue</a> de m'avoir fait découvrir les modes de <a href="http://rapture.io/" target="_blank" rel="nofollow noopener">Rapture</a>.</em></p>]]></description><link>https://david.sferruzza.fr/blog/2016-05-10-conf-gerer-erreurs-scala-devoxxfr/</link><guid isPermaLink="false">https://david.sferruzza.fr/blog/2016-05-10-conf-gerer-erreurs-scala-devoxxfr/</guid><pubDate>Tue, 10 May 2016 14:10:00 GMT</pubDate></item><item><title><![CDATA[Un peu de programmation fonctionnelle en JavaScript !]]></title><description><![CDATA[<blockquote>
<p>Cet article est une très légère variante de celui que j'ai publié dans <a href="http://www.24joursdeweb.fr/2014/un-peu-de-programmation-fonctionnelle-en-javascript/" target="_blank" rel="nofollow noopener">24 jours de web 2014</a>.
Je l'ai aussi adapté en <a href="https://github.com/dsferruzza/talk-programmation-fonctionnelle-en-js" target="_blank" rel="nofollow noopener">présentation</a>.</p>
</blockquote>
<p>Il y a un peu moins de deux ans, j'ai découvert la programmation fonctionnelle.
Je me suis notamment renseigné sur un langage nommé <strong>Haskell</strong>, et je suis tombé sur un article qui énumérait des raisons pour lesquelles l'apprendre valait le coup.
Parmi elles, il y avait la promesse que, même si on n'avait pas l'occasion ou l'intention d'utiliser ce langage tous les jours, l'apprendre permettrait d'être meilleur dans les langages "classiques" (dits <em>impératifs</em>).
Un peu hésitant, j'ai commencé à apprendre et à jouer avec ce nouveau langage...</p>
<p>Au début, c'est déroutant.
On a l'impression de ne plus rien savoir faire : la programmation purement fonctionnelle est un paradigme assez différent de la programmation impérative que l'on pratique dans la plupart des langages populaires.
Mais avec un peu d'efforts, on commence à percevoir les avantages que ça apporte, et croyez-moi, ils sont vraiment intéressants !
Et savez-vous ce qui est encore plus appréciable ?
La promesse est vraie : il est possible, dans une certaine mesure, d'appliquer des concepts de programmation fonctionnelle dans des langages comme JavaScript, et ça permet de faire des programmes plus fiables et plus faciles à maintenir !</p>
<p>Mais vous n'êtes pas obligé de me croire sur parole.
Mon objectif avec cet article est de vous faire entrevoir le gain que l'on peut obtenir en appliquant des concepts de programmation fonctionnelle à des langages impératifs ; en l'occurrence, à JavaScript.</p>
<p>On va commencer en douceur avec quelques concepts théoriques, et puis on fera un peu de pratique en manipulant des tableaux en JavaScript.
Pas besoin d'être Tony Stark, si vous avez déjà fait un peu de JavaScript, et éventuellement vu les fonctions en mathématiques, tout ça devrait vous parler !</p>
<h2>La transparence référentielle</h2>
<p>Avant toute chose, on va parler des fonctions, puisqu'elles sont au cœur de la programmation fonctionnelle.
Voici un exemple de fonction en JavaScript :</p>
<!-- Une fonction est *une routine qui retourne une valeur*.
De manière générale, une fonction possède :

- un nom
- des paramètres d'entrée (chacun a un nom et un type)
- un type de sortie
- un bloc de code (le corps de la fonction), qui va pouvoir utiliser les valeurs fournies en entrée pour calculer une valeur de sortie

On va spécifier toutes ces informations lors de la **définition** de la fonction, et on pourra ensuite **appeler** la fonction pour obtenir la valeur de retour.
En JavaScript, cela se fait comme ça : -->
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// On définit une fonction "ajouterCinq" qui prend un nombre en paramètre,</span>
<span class="token comment">// lui ajoute 5, et renvoie le résultat comme valeur de retour</span>
<span class="token keyword">function</span> <span class="token function">ajouterCinq</span><span class="token punctuation">(</span><span class="token parameter">nombre</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">return</span> nombre <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// On peut maintenant appeler cette fonction pour obtenir un résultat</span>
<span class="token comment">// sans avoir à réécrire toute la logique de calcul à chaque fois</span>

<span class="token function">ajouterCinq</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 5</span>

<span class="token function">ajouterCinq</span><span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 13</span></code></pre></div>
<p>Les fonctions sont très importantes car elles permettent de regrouper les calculs similaires à un seul endroit dans le code, ce qui évite de se répéter et rend le code beaucoup plus lisible.
Elles permettent de découper un problème compliqué en plusieurs problèmes moins compliqués, ce qui est très souvent une bonne idée.</p>
<p>Étudions une autre fonction :</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">diviserParDeux</span><span class="token punctuation">(</span><span class="token parameter">nombre</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">var</span> missile <span class="token operator">=</span> <span class="token function">lancerUnMissileThermonucleaire</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">fairePorterLeChapeauAuDrManhattan</span><span class="token punctuation">(</span>missile<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> nombre <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre></div>
<p>Si on appelle <code class="language-text">diviserParDeux(4)</code>, on obtiendra <code class="language-text">2</code> en valeur de retour.
Mais on voit dans le code de la fonction que celle-ci va appeler d'autres fonctions qui vont visiblement modifier des choses qui sont à l'extérieur de la fonction <code class="language-text">diviserParDeux</code>.
Ce qui est gênant, c'est qu'on n'a pas idée des effets que va avoir l'appel de cette fonction étant donné que cela n'apparait ni dans ces paramètres d'entrée, ni dans sa valeur de retour.
On dit que cette fonction comporte des <strong>effets de bord</strong>.</p>
<p>Notre fonction <code class="language-text">ajouterCinq</code> n'a pas d'effets de bord : elle ne va pas accéder à des zones mémoire qui sont hors de son bloc de code.
On dit que c'est une <strong>fonction pure</strong>.
Et ce qui est pratique avec les fonctions pures, c'est qu'elles retournent toujours le même résultat lorsqu'on les appelle avec les mêmes arguments :</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token function">ajouterCinq</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">4</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token function">ajouterCinq</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">4</span><span class="token punctuation">)</span>
<span class="token comment">// --> 1 == 1</span>
<span class="token comment">// --> true</span>

<span class="token comment">// Alors que cela ne fonctionne pas forcément avec une fonction</span>
<span class="token comment">// qui a des effets de bord</span>
<span class="token keyword">var</span> n <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">ajouterAuCompteur</span><span class="token punctuation">(</span><span class="token parameter">nombre</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	n <span class="token operator">=</span> n <span class="token operator">+</span> nombre<span class="token punctuation">;</span>
	<span class="token comment">// On accède à la variable "n" sans qu'elle ne soit passée en paramètre</span>
	<span class="token comment">// et on la modifie en lui assignant une nouvelle valeur</span>
	<span class="token keyword">return</span> n<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">ajouterAuCompteur</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token function">ajouterAuCompteur</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token comment">// --> 1 == 2</span>
<span class="token comment">// --> false</span></code></pre></div>
<p>Les fonctions pures permettent la <strong>transparence référentielle</strong> : le résultat du programme ne change pas si on remplace une expression par une expression de valeur équivalente.
Dans notre cas, comme on sait que <code class="language-text">ajouterCinq(-4)</code> est strictement équivalent à <code class="language-text">1</code> (car il n'y a pas d'effets de bords), on pourrait remplacer toutes les occurrences de <code class="language-text">ajouterCinq(-4)</code> par <code class="language-text">1</code> dans notre programme sans que ça ne change son résultat.</p>
<p>Si on remplaçait toutes les occurrences de <code class="language-text">diviserParDeux(6)</code> par <code class="language-text">3</code>, on obtiendrait un programme différent car un appel à la fonction <code class="language-text">diviserParDeux(6)</code> a des effets de bord que n'a pas la valeur <code class="language-text">3</code>.</p>
<p>La transparence référentielle est très intéressante car elle rend votre programme facilement prévisible par le lecteur : il devient possible de raisonner dessus comme si c'était une équation, et non plus une séquence d'instructions arbitraires !
Il y a même un terme pour désigner ce concept : <em>equational reasoning</em>.</p>
<p>En s'efforçant de construire son programme avec un maximum de fonctions pures, on va alors se retrouver à isoler les fonctions qui ont des effets de bord, ce qui offre plusieurs avantages :</p>
<ul>
<li>on sait quelles fonctions ont des effets de bord, ce qui permet d'être prudent lorsqu'on les manipule</li>
<li>le cœur du programme, la logique métier, est exprimée avec des fonctions pures qui sont fiables, sans surprises, et aisément testables</li>
</ul>
<p><em>Ne vous inquiétez pas si c'est encore un peu flou ; la prochaine partie sera moins théorique et plus concrète !</em></p>
<h2>Les fonctions d'ordre supérieur</h2>
<p>Dans la partie précédente, je suis rapidement revenu sur ce qu'est une fonction.
Ce que je n'ai pas dit, c'est qu'en JavaScript, les fonctions sont des <strong>objets de première classe</strong>, au même titre que les chaines de caractères, les nombres, et bien d'autres...</p>
<p>Cela veut dire qu'une fonction peut :</p>
<ul>
<li>être expressible comme une valeur anonyme littérale</li>
<li>être affectée à des variables ou des structures de données</li>
<li>avoir une identité intrinsèque</li>
<li>être comparable pour l'égalité ou l'identité avec d'autres entités</li>
<li>être passée comme paramètre à une procédure ou une fonction</li>
<li>être retournée par une procédure ou une fonction</li>
<li>être constructible lors de l'exécution</li>
</ul>
<p>Suivant les langages, les fonctions ne sont pas toujours des objets de première classe : en C, par exemple, ce n'est pas le cas.
Mais quand c'est le cas, cela permet des constructions intéressantes : les <strong>fonctions d'ordre supérieur</strong>.</p>
<p>Une fonction d’ordre supérieur est une fonction qui accepte au moins une autre fonction en paramètre, et/ou qui retourne une fonction en résultat.
C'est tout !
Voyons un exemple :</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// On a une fonction qui accepte un nombre et renvoie ce nombre multiplié par 2</span>
<span class="token keyword">function</span> <span class="token function">multiplierParDeux</span><span class="token punctuation">(</span><span class="token parameter">nombre</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">return</span> nombre <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// On a une autre fonction qui accepte un paramètre quelconque, va l'afficher</span>
<span class="token comment">// et le renvoyer en valeur de retour</span>
<span class="token keyword">function</span> <span class="token function">afficher</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &lt;-- Ceci est un effet de bord</span>
	<span class="token keyword">return</span> x<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Maintenant imaginons qu'on souhaite appliquer multiplierParDeux() sur un nombre,</span>
<span class="token comment">// et ensuite afficher() sur le résultat</span>
<span class="token function">afficher</span><span class="token punctuation">(</span><span class="token function">multiplierParDeux</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 10</span>
<span class="token comment">// --> 10</span>

<span class="token comment">// Cela fonctionne, mais ce n'est pas pratique si on doit s'en servir beaucoup.</span>
<span class="token comment">// Il faudrait avoir une fonction qui fasse les 2 actions directement,</span>
<span class="token comment">// qu'on pourrait appeler afficherDouble()</span>

<span class="token comment">// On pourrait faire comme ça</span>
<span class="token keyword">function</span> <span class="token function">afficherDouble</span><span class="token punctuation">(</span><span class="token parameter">nombre</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">return</span> <span class="token function">afficher</span><span class="token punctuation">(</span><span class="token function">multiplierParDeux</span><span class="token punctuation">(</span>nombre<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Ou on pourrait créer une fonction plus générale</span>
<span class="token comment">// qui pourrait être réutilisée partout !</span>
<span class="token keyword">function</span> <span class="token function">compose</span><span class="token punctuation">(</span><span class="token parameter">f<span class="token punctuation">,</span> g</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token function">f</span><span class="token punctuation">(</span><span class="token function">g</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// compose() accepte deux fonctions (f et g) en paramètre, et renvoie en retour</span>
<span class="token comment">// une fonction (qui est équivalente à la composition de f et g)</span>
<span class="token comment">// C'est donc une fonction d'ordre supérieur !</span>

<span class="token comment">// Ainsi</span>
<span class="token keyword">var</span> afficherDoubleBis <span class="token operator">=</span> <span class="token function">compose</span><span class="token punctuation">(</span>afficher<span class="token punctuation">,</span> multiplierParDeux<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// On indique "afficher" et pas "afficher()" car on veut désigner</span>
<span class="token comment">// la fonction en elle-même, pas l'appeler</span>

<span class="token function">afficherDouble</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token function">afficherDoubleBis</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>
<span class="token comment">// --> true</span></code></pre></div>
<p>Cet exemple, bien qu'un peu abstrait, laisse entrevoir l'intérêt des fonctions d'ordre supérieur : on peut facilement créer des fonctions très générales et les rendre plus spécifiques en leur passant d'autres fonctions en paramètre.
Cela permet de bien séparer les différentes tâches effectuées par nos fonctions.
C'est justement en ayant en tête cette idée de séparer nos traitements en petites fonctions modulaires qu'on va regarder un exemple plus concret : la manipulation des tableaux.</p>
<h3>Les tableaux</h3>
<p>En JavaScript, un tableau peut être vu comme <em>une liste ordonnée de valeurs</em>.
Une valeur peut être un nombre, un objet, une fonction, ... n'importe quel objet de première classe !
Rien ne l'empêche en JavaScript mais, quand on est bien élevé, on évite de faire des tableaux contenant plusieurs types de valeurs :</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> tableau <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Bien</span>
<span class="token keyword">var</span> tableau <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"deux"</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">valeur</span><span class="token operator">:</span> <span class="token number">4</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Mal</span></code></pre></div>
<p>C'est une mauvaise pratique car il devient difficile de raisonner sur les fonctions qui vont manipuler une telle liste.
Une solution serait que chaque élément de la liste soit un élément d'une structure qui permette d'exprimer tous les cas qu'on a besoin d'exprimer ; un objet pourrait faire l'affaire ici.</p>
<p>Les tableaux sont une structure de données extrêmement utile et répandue, et il y a un certain nombre d'opérations qu'on est amené à faire très souvent.
Par exemple, on souhaite souvent transformer chaque élément d'un tableau en quelque chose d'autre.</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// On a une liste d'objets qui représentent des villes</span>
<span class="token comment">// (on peut dire qu'on l'a obtenue grâce à un appel HTTP vers une API externe)</span>
<span class="token keyword">var</span> villes <span class="token operator">=</span> <span class="token punctuation">[</span>
	<span class="token punctuation">{</span> <span class="token literal-property property">nom</span><span class="token operator">:</span> <span class="token string">"Nantes"</span><span class="token punctuation">,</span> <span class="token literal-property property">departement</span><span class="token operator">:</span> <span class="token number">44</span><span class="token punctuation">,</span> <span class="token literal-property property">presDeLaMer</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
	<span class="token punctuation">{</span> <span class="token literal-property property">nom</span><span class="token operator">:</span> <span class="token string">"Dunkerque"</span><span class="token punctuation">,</span> <span class="token literal-property property">departement</span><span class="token operator">:</span> <span class="token number">59</span><span class="token punctuation">,</span> <span class="token literal-property property">presDeLaMer</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
	<span class="token punctuation">{</span> <span class="token literal-property property">nom</span><span class="token operator">:</span> <span class="token string">"Paris"</span><span class="token punctuation">,</span> <span class="token literal-property property">departement</span><span class="token operator">:</span> <span class="token number">75</span><span class="token punctuation">,</span> <span class="token literal-property property">presDeLaMer</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token comment">// On veut obtenir une liste de chaines de type "ville (departement)"</span>
<span class="token keyword">function</span> <span class="token function">rendreVillesAffichables</span><span class="token punctuation">(</span><span class="token parameter">villes</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> villes<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		villes<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> villes<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>nom <span class="token operator">+</span> <span class="token string">" ("</span> <span class="token operator">+</span> villes<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>departement <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> villes<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">rendreVillesAffichables</span><span class="token punctuation">(</span>villes<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// --> ["Nantes (44)", "Dunkerque (59)", "Paris (75)"]</span></code></pre></div>
<p>Le résultat est correct, mais il y a plusieurs problèmes avec cette fonction <code class="language-text">rendreVillesAffichables</code> :</p>
<ol>
<li>Elle modifie le tableau original, ce qui fait qu'elle n'est pas pure : en JavaScript, quand on copie une variable qui contient un tableau ou un objet, seule la référence vers les données est copiée, ce qui fait qu'une modification sur les cases du tableau ou les propriétés de l'objet sera visible depuis la variable originale <strong>et</strong> depuis la copie.</li>
<li>
<p>On a mélangé deux comportements dans notre fonction :</p>
<ul>
<li>parcourir le tableau : c'est quelque chose de très courant, peu importe ce que contient le tableau</li>
<li>effectuer la transformation qu'on souhaite, pour une case donnée : c'est un comportement spécifique, et donc métier, qui se retrouve noyé dans la logique d'itération sur le tableau</li>
</ul>
</li>
</ol>
<p>Certes, l'exemple ici est plutôt simple et concis, mais on peut quand même améliorer ça !</p>
<h3>map</h3>
<p>On pourrait imaginer une fonction d'ordre supérieur qui permette d'abstraire le parcours du tableau.
Cette fonction accepterait deux paramètres : le tableau à transformer, et une fonction effectuant la transformation sur un seul élément du tableau.
Essayons de coder ça !</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">transformerTableau</span><span class="token punctuation">(</span><span class="token parameter">tableau<span class="token punctuation">,</span> transformation</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// On crée un nouveau tableau qu'on va remplir</span>
	<span class="token comment">// plutôt que de modifier celui fourni en paramètre</span>
	<span class="token keyword">var</span> nouveauTableau <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> tableau<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		nouveauTableau<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">transformation</span><span class="token punctuation">(</span>tableau<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> nouveauTableau<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Ainsi, notre fonction rendreVillesAffichables devient :</span>
<span class="token keyword">function</span> <span class="token function">rendreVillesAffichables</span><span class="token punctuation">(</span><span class="token parameter">villes</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">function</span> <span class="token function">rendreUneSeuleVilleAffichable</span><span class="token punctuation">(</span><span class="token parameter">ville</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> ville<span class="token punctuation">.</span>nom <span class="token operator">+</span> <span class="token string">" ("</span> <span class="token operator">+</span> ville<span class="token punctuation">.</span>departement <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> <span class="token function">transformerTableau</span><span class="token punctuation">(</span>villes<span class="token punctuation">,</span> rendreUneSeuleVilleAffichable<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">rendreVillesAffichables</span><span class="token punctuation">(</span>villes<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// --> ["Nantes (44)", "Dunkerque (59)", "Paris (75)"]</span></code></pre></div>
<p>C'est quand même bien plus clair !
La fonction <code class="language-text">transformerTableau</code> n'embarque aucune logique métier et fonctionne avec n'importe quel tableau, et la fonction <code class="language-text">rendreUneSeuleVilleAffichable</code>, qui contient la logique métier de la transformation, est pure, et peut donc être testée très facilement.</p>
<p>Et le plus beau dans tout ça, c'est que notre fonction <code class="language-text">transformerTableau</code> est tellement utile et générique qu'elle est déjà présente dans l'API des tableaux de JavaScript !
Dites bonjour à <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/map" target="_blank" rel="nofollow noopener">Array.map</a> !</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// La même chose que précédemment, mais en utilisant Array.map</span>
<span class="token keyword">function</span> <span class="token function">rendreVillesAffichables</span><span class="token punctuation">(</span><span class="token parameter">villes</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">function</span> <span class="token function">rendreUneSeuleVilleAffichable</span><span class="token punctuation">(</span><span class="token parameter">ville</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> ville<span class="token punctuation">.</span>nom <span class="token operator">+</span> <span class="token string">" ("</span> <span class="token operator">+</span> ville<span class="token punctuation">.</span>departement <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> villes<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>rendreUneSeuleVilleAffichable<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">rendreVillesAffichables</span><span class="token punctuation">(</span>villes<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// --> ["Nantes (44)", "Dunkerque (59)", "Paris (75)"]</span></code></pre></div>
<p>La fonction <code class="language-text">map</code> est présente sur tous les tableaux JavaScript.
Quand on l'appelle, en lui passant en argument une fonction qui accepte un élément du tableau et renvoie le nouvel élément, elle va appliquer cette fonction à chaque case du tableau et renvoyer le résultat sous forme d'un nouveau tableau.</p>
<p>Le tableau de retour a <strong>exactement</strong> le même nombre d'éléments (dans le même ordre) que le tableau d'origine : <code class="language-text">map</code> ne modifie pas la structure (le tableau en lui-même) mais son contenu (les éléments).
<em>Il est tout de même possible en JavaScript de modifier la structure du tableau (en ajoutant ou supprimant des éléments), mais c'est une très mauvaise idée (nous verrons bientôt une solution plus sympathique pour faire ça).</em></p>
<!-- Voici plusieurs propriétés intéressantes de `map` :

```javascript
// La fonction identité :
// Elle renvoie l'argument qu'on lui a fourni sans le modifier
function id(x) {
	return x;
}

// Pour tout tableau
// tableau.map(id) == tableau

// Soient f et g deux fonctions de transformation
// Pour tout tableau
// tableau.map(f).map(g) == tableau.map(compose(f, g))
``` -->
<h3>filter</h3>
<p>Un autre besoin très courant lorsqu'on manipule des tableaux est de vouloir supprimer certains éléments suivant un critère spécifique.
Encore une fois, nous sommes chanceux, il existe une fonction dans l'API des tableaux JavaScript qui fait exactement ça : <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/filter" target="_blank" rel="nofollow noopener">Array.filter</a>.</p>
<p>La fonction <code class="language-text">filter</code> est, comme <code class="language-text">map</code>, présente sur tous les tableaux JavaScript.
Elle a besoin qu'on lui passe une fonction de prédicat, c'est à dire une fonction qui prend un élément comme paramètre et qui renvoie <code class="language-text">true</code> ou <code class="language-text">false</code>.</p>
<p>Par exemple, en partant de notre tableau de villes, on souhaite ne conserver que les villes qui sont près de la mer :</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// Cette fois-ci, plutôt que de créer une fonction nommée,</span>
<span class="token comment">// je passe une fonction anonyme</span>
villes<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// Si la ville est près de la mer, on renvoie true, sinon false</span>
	<span class="token keyword">return</span> item<span class="token punctuation">.</span>presDeLaMer<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// --> [ { nom: "Dunkerque", departement: 59, presDeLaMer: true } ]</span></code></pre></div>
<p>Plutôt chouette, non ?
On peut même <em>chainer</em> <code class="language-text">filter</code> et <code class="language-text">map</code> pour ne garder que les villes qui ne sont pas près de la mer et les afficher de manière élégante :</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">villes<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">return</span> <span class="token operator">!</span>item<span class="token punctuation">.</span>presDeLaMer<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>	<span class="token comment">// Comme villes.filter renvoie un tableau,</span>
			<span class="token comment">// on peut appeler map dessus !</span>
	<span class="token keyword">return</span> item<span class="token punctuation">.</span>nom <span class="token operator">+</span> <span class="token string">" ("</span> <span class="token operator">+</span> item<span class="token punctuation">.</span>departement <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// --> ["Nantes (44)", "Paris (75)"]</span></code></pre></div>
<h3>reduce</h3>
<p>Enfin, on a parfois besoin de transformer un tableau en quelque chose d'autre.
Autrement dit, on ne veut pas toujours conserver intacte la structure qui contient nos données (comme c'est le cas avec <code class="language-text">map</code> et <code class="language-text">filter</code>).
Par exemple, on a un tableau qui contient des objets ayant tous une propriété <code class="language-text">age</code> et on souhaite calculer la somme de tous les âges.</p>
<p>La fonction <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce" target="_blank" rel="nofollow noopener">Array.reduce</a> (également appelée <strong>fold</strong> suivant les langages) est faite pour ça !
Elle a besoin des paramètres suivants : (<em>attention ils ne sont pas dans le bon ordre, mais c'est plus simple à comprendre comme ça</em>)</p>
<ul>
<li>un tableau (<code class="language-text">reduce</code> s'appelle directement sur le tableau, comme <code class="language-text">map</code> et <code class="language-text">filter</code>)</li>
<li>une valeur initiale (elle sera renvoyée si le tableau est vide, notamment)</li>
<li>
<p>une fonction qui accepte deux paramètres :</p>
<ul>
<li>la valeur actuelle de l'<strong>accumulateur</strong> (pour la 1ère itération, c'est la valeur initiale, et pour les suivantes, ce sera la valeur renvoyée par la fonction lors de l'itération précédente)</li>
<li>la valeur de la case du tableau courante</li>
</ul>
</li>
</ul>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> personnes <span class="token operator">=</span> <span class="token punctuation">[</span>
	<span class="token punctuation">{</span> <span class="token literal-property property">nom</span><span class="token operator">:</span> <span class="token string">"Bruce"</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">30</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
	<span class="token punctuation">{</span> <span class="token literal-property property">nom</span><span class="token operator">:</span> <span class="token string">"Tony"</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">35</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
	<span class="token punctuation">{</span> <span class="token literal-property property">nom</span><span class="token operator">:</span> <span class="token string">"Peter"</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">26</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>

personnes<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">acc<span class="token punctuation">,</span> cur</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// On ajoute l'âge courant à la valeur actuelle de la somme</span>
	<span class="token keyword">return</span> acc <span class="token operator">+</span> cur<span class="token punctuation">.</span>age<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// --> 91</span></code></pre></div>
<p><code class="language-text">reduce</code> est très pratique car elle permet de plier (<em>fold</em>) un tableau, ce qui est nécessaire relativement souvent.
Elle est plus générale que <code class="language-text">map</code> et <code class="language-text">filter</code> ; on peut d'ailleurs les exprimer tous les deux en terme de <code class="language-text">reduce</code> :</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">tableau<span class="token punctuation">,</span> transformation</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">return</span> tableau<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">acc<span class="token punctuation">,</span> cur</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		acc<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token function">transformation</span><span class="token punctuation">(</span>cur<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">return</span> acc<span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">tableau<span class="token punctuation">,</span> predicat</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">return</span> tableau<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">acc<span class="token punctuation">,</span> cur</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">predicat</span><span class="token punctuation">(</span>cur<span class="token punctuation">)</span><span class="token punctuation">)</span> acc<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>cur<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">return</span> acc<span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre></div>
<hr>
<p>Pour résumer, si vous avez un tableau et que vous voulez :</p>
<ul>
<li>appliquer une transformation sur chacune de ses cases en conservant leur ordre/nombre : <code class="language-text">map</code></li>
<li>supprimer certaines cases en conservant l'ordre des autres : <code class="language-text">filter</code></li>
<li>le parcourir pour construire une nouvelle structure de données : <code class="language-text">reduce</code></li>
</ul>
<p>Ces fonctions permettent de manipuler des tableaux de manière pure, avec tous les avantages que ça implique.
Je vous encourage à les utiliser, ou à définir vous-même les fonctions d'ordre supérieur dont vous avez besoin !</p>
<h2>Conclusion</h2>
<p>Tout le code ne peut pas être pur, surtout en JavaScript.
Mais plus il l'est, plus il sera clair, réutilisable, fiable et vous fera vous poser les bonnes questions.
Écrire du code qui fonctionne ne suffit pas. La transparence référentielle et les fonctions d'ordre supérieur sont des outils qui vous facilitent grandement la vie lorsque vous réfléchissez sur votre programme.
Elles augmentent la qualité du code que vous écrivez.
Le prix à payer est modique par rapport au gain !</p>
<p>Il existe d'autres concepts très intéressants en programmation fonctionnelle.
On pourrait citer l'évaluation paresseuse, l'immuabilité, ou les systèmes de types avancés.
Ces derniers permettent notamment quelque chose de similaire à l'analyse dimensionnelle en physique : le langage va nous empêcher d'exprimer des incohérences (on ne va pas additionner par erreur une valeur en <code class="language-text">km</code> avec une valeur en <code class="language-text">miles</code>, par exemple).</p>
<p>J'espère que vous avez apprécié cet article !
Voici quelques ressources si vous voulez approfondir un peu ces sujets :</p>
<ul>
<li><a href="http://learnyouahaskell.com/" target="_blank" rel="nofollow noopener">Learn You A Haskell For Great Good</a> : LE livre pour débuter Haskell ; il est très accessible ; disponible en papier ou en ligne (<a href="http://lyah.haskell.fr/" target="_blank" rel="nofollow noopener">traduction FR non officielle</a>)</li>
<li><a href="https://leanpub.com/javascript-allonge" target="_blank" rel="nofollow noopener">JavaScript Alongé</a> : un livre avancé sur JavaScript ; il explique et met en place certains concepts que nous avons survolés ici ; disponible en version dématérialisée ou en ligne</li>
<li><a href="https://lodash.com/" target="_blank" rel="nofollow noopener">Lo-Dash</a> : une bibliothèque JavaScript qui propose notamment des fonctions d'ordre supérieur très intéressantes pour manipuler les collections</li>
<li><a href="https://baconjs.github.io/" target="_blank" rel="nofollow noopener">Bacon.js</a> : une bibliothèque JavaScript qui permet de faire de la programmation fonctionnelle <a href="https://fr.wikipedia.org/wiki/Programmation_r%C3%A9active" target="_blank" rel="nofollow noopener">réactive</a></li>
<li><a href="http://fsharpforfunandprofit.com/posts/is-your-language-unreasonable/" target="_blank" rel="nofollow noopener">Is your programming language unreasonable?</a> <em>or, why predictability is important</em></li>
</ul>
<p><em>Merci à <a href="http://blog.clement.delafargue.name/" target="_blank" rel="nofollow noopener">Clément Delafargue</a>, <a href="http://fgribreau.com/articles/voyage-au-coeur-de-javascript.html" target="_blank" rel="nofollow noopener">Francois-Guillaume Ribreau</a>, <a href="https://twitter.com/mateoelgaco" target="_blank" rel="nofollow noopener">Mathieu Le Gac</a>, <a href="http://elisabeth-hamel.fr/" target="_blank" rel="nofollow noopener">Elisabeth Hamel</a> et <a href="http://tibomahe.com/" target="_blank" rel="nofollow noopener">Thibault Mahé</a> pour leurs relectures !</em></p>]]></description><link>https://david.sferruzza.fr/blog/2015-09-19-un-peu-de-programmation-fonctionnelle-en-js/</link><guid isPermaLink="false">https://david.sferruzza.fr/blog/2015-09-19-un-peu-de-programmation-fonctionnelle-en-js/</guid><pubDate>Sat, 19 Sep 2015 15:20:00 GMT</pubDate></item><item><title><![CDATA[CommaFeed, a self-hosted RSS reader]]></title><description><![CDATA[<h2>Introduction</h2>
<p>A RSS reader (or aggregator) is a software that allows you to read syndicated web content (like news, blog posts, ...) in one unique place.
This is very useful because:</p>
<ul>
<li>you don't have to visit every website/blog you follow to read new articles</li>
<li>you can mark an article as <em>read</em> or <em>unread</em> (like you would do with an email in your inbox)</li>
<li>you can read the content directly inside the reader (which is faster), or click on a link and open it in your browser (which gives you the full experience)</li>
<li>you can let the reader opened all day (my CommaFeed tab in Firefox is pinned, and a little white dot appears on it when there are new articles)</li>
</ul>
<p>CommaFeed is a <em>"Google Reader inspired self-hosted RSS reader"</em>.
You can get the source code on <a href="https://github.com/Athou/commafeed" target="_blank" rel="nofollow noopener">GitHub</a>, and there is a free official instance <a href="https://www.commafeed.com/" target="_blank" rel="nofollow noopener">here</a>.</p>
<p><img src="https://raw.githubusercontent.com/Athou/commafeed/master/src/main/app/images/preview.jpg" alt="A (quite old) preview screenshot"></p>
<p>As CommaFeed is a web application, it doesn't have to run on the same computer you use to read news.
You can host it on a server, so that you can get your unread news and mark them as read no matter where you are.</p>
<p>I will explain how to install you own instance.</p>
<h2>Requirements</h2>
<p>First, you need a server.
A real server, a VPS, or a local virtual machine will do.
In this document, I will assume you have <a href="http://www.debian.org/" target="_blank" rel="nofollow noopener">Debian</a> installed on it, but it's not a requirement.</p>
<p>You will need to have the following packages installed:</p>
<ul>
<li>git</li>
<li>openjdk-7-jdk</li>
<li>maven (3.x)</li>
<li>supervisor</li>
</ul>
<p>Finally, you will need a database server.
Here I will assume you have a MariaDB (or MySQL) server running on localhost, with a <code class="language-text">commafeed:commafeed</code> user that has write access on a <code class="language-text">commafeed</code> database (you can also use PostgreSQL or SQLServer).</p>
<h2>Installation</h2>
<p>First, we create a user and its home:</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">useradd</span> <span class="token parameter variable">-d</span> /opt/commafeed <span class="token parameter variable">-s</span> /bin/bash commafeed
<span class="token function">mkdir</span> /opt/commafeed
<span class="token function">chown</span> commafeed. /opt/commafeed
<span class="token function">su</span> - commafeed</code></pre></div>
<p>Let's clone the repo:</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone https://github.com/Athou/commafeed.git <span class="token builtin class-name">.</span>
<span class="token builtin class-name">cd</span> commafeed</code></pre></div>
<p>Build the project (it can take around 5 minutes):</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">mvn clean package</code></pre></div>
<p>Create the config file:</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">cp</span> config.yml.example config.yml</code></pre></div>
<p>Now, you need to edit <code class="language-text">config.yml</code>.
Get to the <code class="language-text">database</code> section, and put:</p>
<div class="gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">database</span><span class="token punctuation">:</span>
  <span class="token key atrule">driverClass</span><span class="token punctuation">:</span> com.mysql.jdbc.Driver
  <span class="token key atrule">url</span><span class="token punctuation">:</span> jdbc<span class="token punctuation">:</span>mysql<span class="token punctuation">:</span>//localhost/commafeed<span class="token punctuation">?</span>autoReconnect=true<span class="token important">&amp;failOverReadOnly=false&amp;maxReconnects=20&amp;rewriteBatchedStatements=true</span>
  <span class="token key atrule">user</span><span class="token punctuation">:</span> commafeed
  <span class="token key atrule">password</span><span class="token punctuation">:</span> commafeed</code></pre></div>
<p>I also recommend to enable two other options:</p>
<ul>
<li><code class="language-text">pubsubhubbub</code>: to automatically use the <a href="https://code.google.com/p/pubsubhubbub/" target="_blank" rel="nofollow noopener">PubSubHubbub</a> protocol on compatible feeds</li>
<li><code class="language-text">imageProxyEnabled</code>: images in the news will be served through CommaFeed and not directly by the website that published the content</li>
</ul>
<p>Let's try to launch it!</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">java</span> <span class="token parameter variable">-jar</span> target/commafeed.jar server config.yml</code></pre></div>
<p>You should see some log messages in the console while CommaFeed is launching and setting up the database.
Then you can go to <code class="language-text">http://myserver:8082</code> with your web browser (where <code class="language-text">myserver</code> is your server's IP/domain).
You should see the welcome page.
Type <code class="language-text">Ctrl + C</code> in the console to kill CommaFeed.</p>
<p>Now, let's configure <a href="http://supervisord.org/" target="_blank" rel="nofollow noopener">Supervisor</a> to <em>"daemonize"</em> CommaFeed, so that we can launch it automatically on system startup.</p>
<p>Create a <code class="language-text">/etc/supervisor/conf.d/commafeed.conf</code> file (as root) with this content:</p>
<div class="gatsby-highlight" data-language="ini"><pre class="language-ini"><code class="language-ini"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">program:commafeed</span><span class="token punctuation">]</span></span>
<span class="token key attr-name">directory</span><span class="token punctuation">=</span><span class="token value attr-value">/opt/commafeed</span>
<span class="token key attr-name">command</span><span class="token punctuation">=</span><span class="token value attr-value">java -jar target/commafeed.jar server config.yml</span>
<span class="token key attr-name">process_name</span><span class="token punctuation">=</span><span class="token value attr-value">commafeed</span>
<span class="token key attr-name">user</span><span class="token punctuation">=</span><span class="token value attr-value">commafeed</span>
<span class="token key attr-name">autostart</span><span class="token punctuation">=</span><span class="token value attr-value">true</span>
<span class="token key attr-name">autorestart</span><span class="token punctuation">=</span><span class="token value attr-value">true</span></code></pre></div>
<p>Reload Supervisor's config and check if CommaFeed is running:</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">supervisorctl reload
supervisorctl status</code></pre></div>
<p>You should see that CommaFeed is running, and it will keep running even if you close your console.
You can go to <code class="language-text">http://myserver:8082</code>, use <code class="language-text">admin:admin</code> to log in, change <code class="language-text">admin</code> password (or disable <code class="language-text">admin</code> user), create a new user and start using it!</p>
<h2>Using a custom HTTP frontend</h2>
<p>CommaFeed works, but you might want more, like accessing it on port 80 or 443 (with SSL) using a virtual host (so you can host other apps reachable via port 80/443).</p>
<p>In this document, I will use Apache2, but you can setup a similar configuration with any decent HTTP server.</p>
<p>First, install the <code class="language-text">apache2</code> package.</p>
<p>If you want SSL, you need to add the following line in <code class="language-text">/etc/apache2/ports.conf</code>:</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">NameVirtualHost *:443</code></pre></div>
<p>It allows Apache to use virtual hosts on port 443<sup id="fnref-1"><a href="#fn-1" class="footnote-ref">1</a></sup>.
Then, let's enable some mods:</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">a2enmod proxy proxy_http ssl</code></pre></div>
<p>For SSL, I will assume that you have already created a certificate and its key<sup id="fnref-2"><a href="#fn-2" class="footnote-ref">2</a></sup> in a <code class="language-text">/etc/commafeed</code> directory (it can be anywhere as long as the web server's user can read it).</p>
<p>Now we can create a virtual host in <code class="language-text">/etc/apache2/sites-available/commafeed</code>:</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">&lt;VirtualHost *:443>
    ServerName rss.mydomain.com

    &lt;IfModule mod_ssl.c>
        SSLEngine on
        SSLCertificateFile /etc/commafeed/commafeed.pem
        SSLCertificateKeyFile /etc/commafeed/commafeed.key
    &lt;/IfModule>

    &lt;IfModule mod_proxy.c>
        ProxyRequests off
        ProxyVia on
        ProxyPass / http://localhost:8082/
        ProxyPassReverse / http://localhost:8082/
        &lt;Proxy *>
            Order deny,allow
            Allow from all
        &lt;/Proxy>
    &lt;/IfModule>
&lt;/VirtualHost></code></pre></div>
<p>Or, if you don't want SSL:</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">&lt;VirtualHost *:80>
    ServerName rss.mydomain.com

    &lt;IfModule mod_proxy.c>
        ProxyRequests off
        ProxyVia on
        ProxyPass / http://localhost:8082/
        ProxyPassReverse / http://localhost:8082/
        &lt;Proxy *>
            Order deny,allow
            Allow from all
        &lt;/Proxy>
    &lt;/IfModule>
&lt;/VirtualHost></code></pre></div>
<p>Now, we can enable it, and restart Apache:</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">a2ensite commafeed
<span class="token function">service</span> apache restart</code></pre></div>
<p>Last thing, we need to update the <code class="language-text">app.publicUrl</code> key in CommaFeed's config:</p>
<div class="gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">app</span><span class="token punctuation">:</span>
  <span class="token comment"># url used to access commafeed</span>
  <span class="token key atrule">publicUrl</span><span class="token punctuation">:</span> https<span class="token punctuation">:</span>//rss.mydomain.com</code></pre></div>
<p>Restart CommaFeed:</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">supervisorctl restart commafeed</code></pre></div>
<p>And head over to <code class="language-text">https://rss.mydomain.com</code>!</p>
<h2>Update</h2>
<p>If you want to update CommaFeed, here is a simple script:</p>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token shebang important">#!/bin/sh</span>

<span class="token builtin class-name">cd</span> /opt/commafeed
<span class="token function">su</span> commafeed <span class="token parameter variable">-c</span> <span class="token string">"git pull"</span>
<span class="token function">su</span> commafeed <span class="token parameter variable">-c</span> <span class="token string">"mvn clean package"</span>
supervisorctl restart commafeed
supervisorctl <span class="token function">tail</span> <span class="token parameter variable">-f</span> commafeed</code></pre></div>
<p>Pay attention to the list of modified files displayed when the <code class="language-text">git pull</code> command is executed: if <code class="language-text">config.yml.example</code> has changed, you might need to take a look and edit <code class="language-text">config.yml</code>.</p>
<h2>Share the love</h2>
<p>If (like me) you think CommaFeed is a great software, share the love by:</p>
<ul>
<li>using it</li>
<li>telling your friends about it</li>
<li>giving some <a href="https://github.com/Athou/commafeed/issues" target="_blank" rel="nofollow noopener">feedback</a></li>
<li>translating it</li>
<li>improving it</li>
<li>giving it a <a href="https://flattr.com/thing/1409652/Athoucommafeed-on-GitHub" target="_blank" rel="nofollow noopener">Flattr</a></li>
</ul>
<p><em>I'm not affiliated with this project, but I'm using it everyday for a while (and sometimes reporting bugs).</em></p>
<div class="footnotes">
<hr>
<ol>
<li id="fn-1">
<p>See <a href="https://httpd.apache.org/docs/2.2/mod/core.html#NameVirtualHost" target="_blank" rel="nofollow noopener">https://httpd.apache.org/docs/2.2/mod/core.html#NameVirtualHost</a> for more details</p>
<a href="#fnref-1" class="footnote-backref">↩</a>
</li>
<li id="fn-2">
<p>Have a look to this guide: <a href="https://wiki.debian.org/Self-Signed_Certificate" target="_blank" rel="nofollow noopener">https://wiki.debian.org/Self-Signed_Certificate</a></p>
<a href="#fnref-2" class="footnote-backref">↩</a>
</li>
</ol>
</div>]]></description><link>https://david.sferruzza.fr/blog/2014-08-18-how-to-install-commafeed-rss-reader/</link><guid isPermaLink="false">https://david.sferruzza.fr/blog/2014-08-18-how-to-install-commafeed-rss-reader/</guid><pubDate>Mon, 18 Aug 2014 16:04:00 GMT</pubDate></item><item><title><![CDATA[New blog with Hakyll!]]></title><description><![CDATA[<p><em>Update: I do not use this system anymore, but this article may still be helpful.</em></p>
<h2>Why?</h2>
<p>I had this <em>« make yourself a decent website »</em> task on my todo list for more than a year.
As I am more and more interested in what I do, I decided it was time to begin to give back and share some stuff I like.</p>
<p>Also, the <em>« I should totally write a blog post about that! »</em> situation happened too many times repeatedly these last weeks.</p>
<p>I think I will mostly write about Computer Science/Programming, and projects I like and/or make.
But who knows...</p>
<h2>How?</h2>
<p>The first thing I want to write about is how I made this website/blog.</p>
<p>I used a <a href="http://haskell.org/" target="_blank" rel="nofollow noopener">Haskell</a> library called <a href="http://jaspervdj.be/hakyll/" target="_blank" rel="nofollow noopener">Hakyll</a>.
Hakyll makes it easy to build a static website generator.</p>
<p>There are lots of static website generators[^1], but Hakyll is the best I tried.
It is <strong>fast</strong>, while being <strong>highly customizable</strong>.
And it can handle many cool stuff almost out-of-the-box, including:</p>
<ul>
<li>templating</li>
<li>markdown (and many other formats, because it uses <a href="http://johnmacfarlane.net/pandoc/" target="_blank" rel="nofollow noopener">Pandoc</a>)</li>
<li>incremental build (you don't have to rebuild everything on every modification)</li>
<li>CSS compression</li>
<li>tags and metadata</li>
<li>RSS/Atom feeds</li>
<li>...</li>
</ul>
<p>Making a static website by hand can be painful.
To avoid repeating code, people often use dynamic languages (such as PHP).
But this sounds like a waste to me: on each request, the server has to compute the same operations over and over to serve the same page, just because the developer wants DRY[^2] code.
This makes sense when you need to handle user inputs, but that is not always the case.
For that kind of projects, Hakyll is a really nice tool.</p>
<p>You can find the source code here: <a href="https://github.com/dsferruzza/david.sferruzza.fr" target="_blank" rel="nofollow noopener">https://github.com/dsferruzza/david.sferruzza.fr</a></p>
<h2>Some little details</h2>
<p>Two static website generators are never exactly the same (that's the point).
So building one involves picking up some stuff from the example site, or from <a href="http://jaspervdj.be/hakyll/examples.html" target="_blank" rel="nofollow noopener">nice people</a>, and developing the rest.</p>
<p>I will quickly show some of these features I picked up or developed.</p>
<p>I'm still a beginner, so <strong>if you have better solutions, please let me know!</strong></p>
<h3>Links in feed</h3>
<p>As I said, Hakyll is able to generate RSS and Atom feeds[^3].
While generating a post's page, we will tell Hakyll to take a snapshot of the result, just after converting the post's markdown to HTML, and just before applying it to a template.
This snapshot will then be put in the feed.</p>
<p><em>But what if a post contains a relative link?</em></p>
<p>Well, it will stay relative, and that's what we want for the post's page.
But we don't want that for the feed, because feed readers won't be able to resolve it.</p>
<p>A solution would be to use the <code class="language-text">xml:base</code>[^4] attribute in a root element of the feed.
The feed <a href="https://github.com/jaspervdj/hakyll/blob/master/src/Hakyll/Web/Feed.hs#L122" target="_blank" rel="nofollow noopener">rendering function</a> let me think it would be possible to override the <a href="https://github.com/jaspervdj/hakyll/tree/master/data/templates" target="_blank" rel="nofollow noopener">default feed templates</a>.
But I don't know if it is possible yet, nor how to do it...</p>
<p>So I picked up <a href="https://github.com/divarvel/blog/blob/master/Main.hs#L31-L33" target="_blank" rel="nofollow noopener">another solution</a> from <a href="http://blog.clement.delafargue.name" target="_blank" rel="nofollow noopener">Clément Delafargue's blog</a>.
When generating posts' pages, Hakyll will resolve relative links before taking a snapshot for the feed, and then transform them back so that they will be relative in the rendered page (but not in the feed).</p>
<p>I believe that the first solution would be cleaner, but the second works nicely.</p>
<h3>Update date</h3>
<p>When I update a blog post, I want the date of the update to appear in the blog's page, but also in the feed (using <code class="language-text">&lt;updated></code> tags).</p>
<p>Hakyll handles that with a <code class="language-text">modificationTimeField</code>[^5] you can add to your post's context.
But I don't really like the idea of the modification date only be kept on my file system.
I want to be able to clone my blog's Git repository, build it and get exactly the same result every time.
This would not be the case if I use a <code class="language-text">modificationTimeField</code>, because Git don't store files' modification date.</p>
<p>So I created a <code class="language-text">updatedField</code>, which is implemented exactly like <code class="language-text">dateField</code> except that it only tries to get the date from a <code class="language-text">updated</code> field in my content's metadata.</p>
<div class="gatsby-highlight" data-language="haskell"><pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">updatedField</span> <span class="token operator">::</span> <span class="token constant">String</span> <span class="token operator">-></span> <span class="token constant">String</span> <span class="token operator">-></span> <span class="token constant">Context</span> <span class="token hvariable">a</span>
<span class="token hvariable">updatedField</span> <span class="token hvariable">key</span> <span class="token hvariable">format</span> <span class="token operator">=</span> <span class="token hvariable">field</span> <span class="token hvariable">key</span> <span class="token operator">$</span> <span class="token operator">\</span><span class="token hvariable">i</span> <span class="token operator">-></span> <span class="token keyword">do</span>
    <span class="token hvariable">time</span> <span class="token operator">&lt;-</span> <span class="token hvariable">getUpdatedTime</span> <span class="token hvariable">locale</span> <span class="token operator">$</span> <span class="token hvariable">itemIdentifier</span> <span class="token hvariable">i</span>
    <span class="token builtin">return</span> <span class="token operator">$</span> <span class="token hvariable">formatTime</span> <span class="token hvariable">locale</span> <span class="token hvariable">format</span> <span class="token hvariable">time</span>
  <span class="token keyword">where</span>
    <span class="token hvariable">locale</span> <span class="token operator">=</span> <span class="token hvariable">defaultTimeLocale</span>

<span class="token hvariable">getUpdatedTime</span> <span class="token operator">::</span> <span class="token constant">MonadMetadata</span> <span class="token hvariable">m</span> <span class="token operator">=></span> <span class="token constant">TimeLocale</span> <span class="token operator">-></span> <span class="token constant">Identifier</span> <span class="token operator">-></span> <span class="token hvariable">m</span> <span class="token constant">UTCTime</span>
<span class="token hvariable">getUpdatedTime</span> <span class="token hvariable">locale</span> <span class="token builtin">id</span>' <span class="token operator">=</span> <span class="token keyword">do</span>
    <span class="token hvariable">metadata</span> <span class="token operator">&lt;-</span> <span class="token hvariable">getMetadata</span> <span class="token builtin">id</span>'
    <span class="token keyword">let</span> <span class="token hvariable">tryField</span> <span class="token hvariable">k</span> <span class="token hvariable">fmt</span> <span class="token operator">=</span> <span class="token constant">M</span><span class="token punctuation">.</span><span class="token builtin">lookup</span> <span class="token hvariable">k</span> <span class="token hvariable">metadata</span> <span class="token operator">>>=</span> <span class="token hvariable">parseTime'</span> <span class="token hvariable">fmt</span>
    <span class="token builtin">maybe</span> <span class="token hvariable">empty'</span> <span class="token builtin">return</span> <span class="token operator">$</span> <span class="token hvariable">msum</span> <span class="token operator">$</span> <span class="token punctuation">[</span><span class="token hvariable">tryField</span> <span class="token string">"updated"</span> <span class="token hvariable">fmt</span> <span class="token operator">|</span> <span class="token hvariable">fmt</span> <span class="token operator">&lt;-</span> <span class="token hvariable">formats</span><span class="token punctuation">]</span>
  <span class="token keyword">where</span>
    <span class="token hvariable">empty'</span>     <span class="token operator">=</span> <span class="token builtin">fail</span> <span class="token operator">$</span> <span class="token string">"getUpdatedTime: "</span> <span class="token operator">++</span>
        <span class="token string">"could not parse time for "</span> <span class="token operator">++</span> <span class="token builtin">show</span> <span class="token builtin">id</span>'
    <span class="token hvariable">parseTime'</span> <span class="token operator">=</span> <span class="token hvariable">parseTime</span> <span class="token hvariable">locale</span>
    <span class="token hvariable">formats</span>    <span class="token operator">=</span>
        <span class="token punctuation">[</span> <span class="token string">"%a, %d %b %Y %H:%M:%S %Z"</span>
        <span class="token punctuation">,</span> <span class="token string">"%Y-%m-%dT%H:%M:%S%Z"</span>
        <span class="token punctuation">,</span> <span class="token string">"%Y-%m-%d %H:%M:%S%Z"</span>
        <span class="token punctuation">,</span> <span class="token string">"%Y-%m-%d"</span>
        <span class="token punctuation">,</span> <span class="token string">"%B %e, %Y %l:%M %p"</span>
        <span class="token punctuation">,</span> <span class="token string">"%B %e, %Y"</span>
        <span class="token punctuation">,</span> <span class="token string">"%b %d, %Y"</span>
        <span class="token punctuation">]</span></code></pre></div>
<p>Now, if I want to indicate that I updated a post, I just need to add something like <code class="language-text">updated: 2014-12-01 12:30:00+02:00</code> in the post's metadata.
It will be synced by Git :)</p>
<h3>ISO 8601 dates</h3>
<p>I wanted to use <code class="language-text">&lt;time></code>[^6] tags in my posts' pages.
<code class="language-text">&lt;time></code> tags binds a machine-readable date to a human-readable date.
This means we need a machine-readable date.</p>
<p>I picked up a <a href="https://github.com/jtanguy/julien.jhome.fr/blob/master/bin/blog.hs#L160" target="_blank" rel="nofollow noopener">quite simple solution</a> from <a href="http://julien.jhome.fr/" target="_blank" rel="nofollow noopener">Julien Tanguy's blog</a>.
You just need to add a new <code class="language-text">dateField</code> to the post's context.
This <code class="language-text">dateField</code> would have a <em>format</em> argument like that: <code class="language-text">(iso8601DateFormat Nothing)</code>.</p>
<h3>Cabal sandbox</h3>
<p>When you install Hakyll following the <a href="http://jaspervdj.be/hakyll/tutorials/01-installation.html" target="_blank" rel="nofollow noopener">official tutorial</a>, you type <code class="language-text">cabal install hakyll</code>, which installs globally the latest version of Hakyll.
In a previous project, I had some troubles when I started to update this globally-installed Hakyll.</p>
<p>So I decided I will use a sandbox this time.</p>
<blockquote>
<p>Sandboxes ( in cabal > 1.18 ) are self contained environments of Haskell packages.[^7]</p>
</blockquote>
<p>My haskell's dependencies (including Hakyll) are written in a <code class="language-text">.cabal</code> file.
Then it's easy:</p>
<ul>
<li><code class="language-text">cabal sandbox init</code> to initialize the sandbox</li>
<li><code class="language-text">cabal install --dependencies-only</code> to install dependencies</li>
</ul>
<p>It seems like, in a near future, Hakyll will generate the <code class="language-text">.cabal</code> file when doing a <code class="language-text">hakyll-init my-site</code>[^8].</p>
<h3>Comments</h3>
<p>Of course, it is not possible to make a comment system using Hakyll.
But it is possible to integrate one.</p>
<p>I was lazy so I choose to use Disqus.
As it includes a lot of stuff (Google Analytics, ~ 700 ko of data which is around 200% of this page's size without comments), I don't let it load itself automatically.</p>
<p>I made something <em>quick and dirty</em> to do so:</p>
<div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>disqus_thread<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#disqus_thread<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">disqus</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Load comments<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
	<span class="token keyword">function</span> <span class="token function">disqus</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token comment">// Disqus code</span>
	<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre></div>
<p><strong>You should give <a href="http://jaspervdj.be/hakyll" target="_blank" rel="nofollow noopener">Hakyll</a> a try!</strong></p>
<p>[^1]: Someone even made <a href="http://staticsitegenerators.net/" target="_blank" rel="nofollow noopener">a website to list them</a>
[^2]: Don't Repeat Yourself
[^3]: See <a href="http://jaspervdj.be/hakyll/tutorials/05-snapshots-feeds.html" target="_blank" rel="nofollow noopener">the official tutorial</a>
[^4]: See <a href="https://developer.mozilla.org/en-US/docs/XML/xml:base" target="_blank" rel="nofollow noopener">https://developer.mozilla.org/en-US/docs/XML/xml:base</a>
[^5]: See <a href="http://jaspervdj.be/hakyll/reference/Hakyll-Web-Template-Context.html#v:modificationTimeField" target="_blank" rel="nofollow noopener">http://jaspervdj.be/hakyll/reference/Hakyll-Web-Template-Context.html#v:modificationTimeField</a>
[^6]: Specification: <a href="http://www.w3.org/TR/html5/text-level-semantics.html#the-time-element" target="_blank" rel="nofollow noopener">http://www.w3.org/TR/html5/text-level-semantics.html#the-time-element</a>
[^7]: I took this quote from <a href="http://dev.stephendiehl.com/hask/" target="_blank" rel="nofollow noopener">http://dev.stephendiehl.com/hask/</a>
[^8]: According to <a href="https://github.com/jaspervdj/hakyll/issues/267" target="_blank" rel="nofollow noopener">https://github.com/jaspervdj/hakyll/issues/267</a></p>]]></description><link>https://david.sferruzza.fr/blog/2014-06-18-new-blog-with-hakyll/</link><guid isPermaLink="false">https://david.sferruzza.fr/blog/2014-06-18-new-blog-with-hakyll/</guid><pubDate>Tue, 17 Jun 2014 22:10:00 GMT</pubDate></item></channel></rss>