ability to build org mode + pres Haskell

This commit is contained in:
Yann Esposito (Yogsototh) 2018-04-05 18:49:03 +02:00
parent 16e32f1f7f
commit fa66e280b4
Signed by untrusted user who does not match committer: yogsototh
GPG key ID: 7B19A4C650D59646
18 changed files with 2660 additions and 11 deletions

Binary file not shown.

Binary file not shown.

View file

@ -60,7 +60,7 @@ main = do
-- | Find Markdown Files (skip hidden directories)
findMarkdownFiles :: Shell FilePath
findMarkdownFiles = do
fic <- find (suffix ".md") "." & fgrep (invert (prefix "./."))
fic <- find (choice [(suffix ".md"), (suffix ".org")]) "." & fgrep (invert (prefix "./."))
let mf = stripPrefix "./" fic
_ <- guard (isJust mf)
return (fromJust mf)

Binary file not shown.

View file

@ -15,8 +15,8 @@
<body>
<header>
<h1 class="title">Druid for real-time analysis</h1>
<h2 class="author">Yann Esposito</h2>
<h3 class="date">7 Avril 2016</h3>
<p class="author">Yann Esposito</p>
<p class="date">7 Avril 2016</p>
</header>
<nav id="TOC">
<ul>

Binary file not shown.

Binary file not shown.

View file

@ -16,8 +16,8 @@
<body>
<header>
<h1 class="title">Welcome to <code>mkdocs</code></h1>
<h2 class="author">Yann Esposito</h2>
<h3 class="date">26 July 2016</h3>
<p class="author">Yann Esposito</p>
<p class="date">26 July 2016</p>
</header>
<nav id="TOC">
<ul>

BIN
index.pdf

Binary file not shown.

Binary file not shown.

869
pres-Haskell-Intro.html Normal file
View file

@ -0,0 +1,869 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta name="author" content="Yann Esposito">
<title>Introduction à la Programmation Fonctionnelle en Haskell</title>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
</style>
<link rel="stylesheet" href="styling.css">
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<header>
<h1 class="title">Introduction à la Programmation Fonctionnelle en Haskell</h1>
<p class="author">Yann Esposito</p>
<p class="date">&lt;2018-03-15 Thu&gt;</p>
</header>
<nav id="TOC">
<ul>
<li><a href="#courte-introduction">Courte Introduction</a><ul>
<li><a href="#prelude">Prelude</a></li>
<li><a href="#parcours-jusquà-haskell">Parcours jusquà Haskell</a><ul>
<li><a href="#parcours-pro">Parcours Pro</a></li>
<li><a href="#langages-de-programmations-basiques">Langages de programmations basiques</a></li>
<li><a href="#langages-de-programmations-orientés-objet">Langages de programmations orientés objet</a></li>
<li><a href="#langages-moderne-de-script">Langages moderne de script</a></li>
<li><a href="#langage-peu-reconnus">Langage peu (re)connus</a></li>
<li><a href="#langages-fonctionnels">Langages fonctionnels</a></li>
</ul></li>
<li><a href="#quest-ce-que-la-programmation-fonctionnelle">Quest-ce que la programmation fonctionnelle?</a><ul>
<li><a href="#von-neumann-architecture">Von Neumann Architecture</a></li>
<li><a href="#von-neumann-vs-church">Von Neumann vs Church</a></li>
<li><a href="#histoire">Histoire</a></li>
<li><a href="#retour-dexpérience-subjectif">Retour dexpérience subjectif</a></li>
</ul></li>
<li><a href="#pourquoi-haskell">Pourquoi Haskell?</a><ul>
<li><a href="#simplicité-par-labstraction">Simplicité par labstraction</a></li>
<li><a href="#production-ready">Production Ready™</a></li>
<li><a href="#tooling">Tooling</a></li>
<li><a href="#qualité">Qualité</a></li>
</ul></li>
</ul></li>
<li><a href="#premiers-pas-en-haskell">Premiers Pas en Haskell</a><ul>
<li><a href="#hello-world-13">Hello World! (1/3)</a></li>
<li><a href="#hello-world-23">Hello World! (2/3)</a></li>
<li><a href="#hello-world-33">Hello World! (3/3)</a></li>
<li><a href="#what-is-your-name">What is your name?</a><ul>
<li><a href="#what-is-your-name-13">What is your name? (1/3)</a></li>
<li><a href="#what-is-your-name-23">What is your name? (2/3)</a></li>
<li><a href="#what-is-your-name-33">What is your name? (3/3)</a></li>
</ul></li>
<li><a href="#erreurs-classiques">Erreurs classiques</a><ul>
<li><a href="#erreur-classique-1">Erreur classique #1</a></li>
<li><a href="#erreur-classique-1-1">Erreur classique #1</a></li>
<li><a href="#erreur-classique-2">Erreur classique #2</a></li>
<li><a href="#erreur-classique-2-fix">Erreur classique #2 (fix)</a></li>
</ul></li>
</ul></li>
<li><a href="#concepts-avec-exemples">Concepts avec exemples</a><ul>
<li><a href="#concepts">Concepts</a></li>
<li><a href="#pureté-function-vs-proceduresubroutines"><em>Pureté</em>: Function vs Procedure/Subroutines</a></li>
<li><a href="#pureté-function-vs-proceduresubroutines-exemple"><em>Pureté</em>: Function vs Procedure/Subroutines (exemple)</a></li>
<li><a href="#pureté-gain-paralellisation-gratuite"><em>Pureté</em>: Gain, paralellisation gratuite</a></li>
<li><a href="#pureté-structures-de-données-immuable"><em>Pureté</em>: Structures de données immuable</a></li>
<li><a href="#évaluation-parraisseuse-stratégies-dévaluations"><em>Évaluation parraisseuse</em>: Stratégies dévaluations</a></li>
<li><a href="#évaluation-parraisseuse-exemple-1"><em>Évaluation parraisseuse</em>: Exemple 1</a></li>
<li><a href="#évaluation-parraisseuse-structures-de-données-infinies-zip"><em>Évaluation parraisseuse</em>: Structures de données infinies (zip)</a></li>
<li><a href="#adt-typage-polymorphique"><em>ADT &amp; Typage polymorphique</em></a></li>
<li><a href="#adt-typage-polymorphique-inférence-de-type"><em>ADT &amp; Typage polymorphique</em>: Inférence de type</a></li>
<li><a href="#composabilité">Composabilité</a><ul>
<li><a href="#composabilité-vs-modularité">Composabilité vs Modularité</a></li>
<li><a href="#exemples">Exemples</a></li>
</ul></li>
</ul></li>
<li><a href="#catégories-de-bugs-évités-avec-haskell">Catégories de bugs évités avec Haskell</a><ul>
<li><a href="#real-productions-bugs">Real Productions Bugs™</a></li>
<li><a href="#null-pointer-exception-erreur-classique-1">Null Pointer Exception: Erreur classique (1)</a></li>
<li><a href="#null-pointer-exception-erreur-classique-2">Null Pointer Exception: Erreur classique (2)</a></li>
<li><a href="#null-pointer-exception-data-type-maybe">Null Pointer Exception: Data type <code>Maybe</code></a></li>
<li><a href="#null-pointer-excepton-etat">Null Pointer Excepton: Etat</a></li>
<li><a href="#erreur-due-à-une-typo">Erreur due à une typo</a></li>
<li><a href="#echange-de-parameters">Echange de parameters</a></li>
<li><a href="#changement-intempestif-dun-etat-global">Changement intempestif dun Etat Global</a></li>
</ul></li>
<li><a href="#organisation-du-code">Organisation du Code</a><ul>
<li><a href="#grands-concepts">Grands Concepts</a></li>
<li><a href="#monades">Monades</a></li>
<li><a href="#effets">Effets</a></li>
<li><a href="#exemple-dans-un-code-réel-1">Exemple dans un code réel (1)</a></li>
<li><a href="#exemple-dans-un-code-réel-2">Exemple dans un code réel (2)</a></li>
<li><a href="#règles-pragmatiques">Règles <strong>pragmatiques</strong></a><ul>
<li><a href="#organisation-en-fonction-de-la-complexité">Organisation en fonction de la complexité</a></li>
<li><a href="#couches">3 couches</a></li>
<li><a href="#services-lib">Services / Lib</a></li>
</ul></li>
</ul></li>
<li><a href="#conclusion">Conclusion</a><ul>
<li><a href="#pourquoi-haskell-1">Pourquoi Haskell?</a></li>
<li><a href="#avantage-compétitif">Avantage compétitif</a></li>
</ul></li>
<li><a href="#appendix">Appendix</a><ul>
<li><a href="#stm-exemple-concurrence-12">STM: Exemple (Concurrence) (1/2)</a></li>
<li><a href="#stm-exemple-concurrence-22">STM: Exemple (Concurrence) (2/2)</a></li>
</ul></li>
</ul>
</nav>
<h1 id="courte-introduction">Courte Introduction</h1>
<h2 id="prelude">Prelude</h2>
<p>Initialiser lenv de dev:</p>
<pre class="shell"><code>curl -sSL https://get.haskellstack.org/ | sh
stack new ipfh https://git.io/vbpej &amp;&amp; \
cd ipfh &amp;&amp; \
stack setup &amp;&amp; \
stack build &amp;&amp; \
stack test &amp;&amp; \
stack bench
</code></pre>
<h2 id="parcours-jusquà-haskell">Parcours jusquà Haskell</h2>
<h3 id="parcours-pro">Parcours Pro</h3>
<ul>
<li>Doctorat (machine learning, hidden markov models) 2004</li>
<li>Post doc (écriture dun UI pour des biologistes en Java). 2006</li>
<li>Dev Airfrance, (Perl, scripts shell, awk, HTML, CSS, JS, XML…) 2006 → 2013</li>
<li>Dev (ruby, C, ML) pour GridPocket. (dev) 2009 → 2011, (impliqué) 2009 →</li>
<li>Clojure dev &amp; Machine Learning pour Vigiglobe. 2013 → 2016</li>
<li>Senior Clojure développeur chez Cisco. 2016 →</li>
</ul>
<h3 id="langages-de-programmations-basiques">Langages de programmations basiques</h3>
<ol>
<li>BASIC (MO5, Amstrad CPC 6129, Atari STf)</li>
<li>Logo (école primaire, + écriture dun cours en 1ère année de Fac)</li>
<li>Pascal (lycée, fac)</li>
<li>C (fac)</li>
<li>ADA (fac)</li>
</ol>
<h3 id="langages-de-programmations-orientés-objet">Langages de programmations orientés objet</h3>
<ol>
<li>C++ (fac + outils de recherche pour doctorat)</li>
<li>Eiffel (fac)</li>
<li>Java (fac, UI en Java 1.6, Swing pour postdoc)</li>
<li>Objective-C (temps personnel, app iPhone, app Mac, Screensavers)</li>
</ol>
<h3 id="langages-moderne-de-script">Langages moderne de script</h3>
<ol>
<li>PHP (fac, site perso)</li>
<li>Python (fac, projets perso, jeux, etc…)</li>
<li>Awk (fac, Airfrance, …)</li>
<li>Perl (Airfrance…)</li>
<li>Ruby (GridPocket, site perso v2)</li>
<li>Javascript:
<ul>
<li><em>Airfrance</em> basic prototype, jquery, etc..,</li>
<li>spine.js</li>
<li>backbone.js</li>
<li>Coffeescript</li>
<li>Cappuccino (Objective-J)</li>
<li>Sproutcore</li>
<li><em>Vigiglobe</em> actionhero (nodejs), angularjs v1</li>
</ul></li>
</ol>
<h3 id="langage-peu-reconnus">Langage peu (re)connus</h3>
<ol>
<li>Metapost</li>
<li>zsh (quasi lang de prog)</li>
<li>prolog</li>
</ol>
<h3 id="langages-fonctionnels">Langages fonctionnels</h3>
<ol>
<li>CamL</li>
<li>Haskell (Vigiglobe, personnal)</li>
<li>Clojure (Vigiglobe, Cisco)</li>
</ol>
<h2 id="quest-ce-que-la-programmation-fonctionnelle">Quest-ce que la programmation fonctionnelle?</h2>
<h3 id="von-neumann-architecture">Von Neumann Architecture</h3>
<pre><code> +--------------------------------+
| +----------------------------+ |
| | central processing unit | |
| | +------------------------+ | |
| | | Control Unit | | |
+------+ | | +------------------------+ | | +--------+
|input +---&gt; | +------------------------+ | +--&gt; output |
+------+ | | | Arithmetic/Logic Unit | | | +--------+
| | +------------------------+ | |
| +-------+---^----------------+ |
| | | |
| +-------v---+----------------+ |
| | Memory Unit | |
| +----------------------------+ |
+--------------------------------+
</code></pre>
<p>made with <a href="http://asciiflow.com" class="uri">http://asciiflow.com</a></p>
<h3 id="von-neumann-vs-church">Von Neumann vs Church</h3>
<ul>
<li>programmer à partir de la machine (Von Neumann)
<ul>
<li>tire vers loptimisation</li>
<li>mots de bits, caches, détails de bas niveau</li>
<li>actions séquentielles</li>
<li><strong>1 siècle dexpérience</strong></li>
</ul></li>
</ul>
<div class="incremental">
<ul>
<li>programmer comme manipulation de symbole (Alonzo Church)
<ul>
<li>tire vers labstraction</li>
<li>plus proche des représentations mathématiques</li>
<li>ordre dévaluation non imposé</li>
<li><strong>4000 ans dexpérience</strong></li>
</ul></li>
</ul>
</div>
<h3 id="histoire">Histoire</h3>
<ul>
<li>λ-Calculus, Alonzo Church &amp; Rosser 1936
<ul>
<li>Foundation, explicit side effect no implicit state</li>
</ul></li>
</ul>
<div class="incremental">
<ul>
<li>LISP (McCarthy 1960)
<ul>
<li>Garbage collection, higher order functions, dynamic typing</li>
</ul></li>
</ul>
</div>
<div class="incremental">
<ul>
<li>ML (1969-80)
<ul>
<li>Static typing, Algebraic Datatypes, Pattern matching</li>
</ul></li>
</ul>
</div>
<div class="incremental">
<ul>
<li>Miranda (1986) → Haskell (1992‥)
<ul>
<li>Lazy evaluation, pure</li>
</ul></li>
</ul>
</div>
<h3 id="retour-dexpérience-subjectif">Retour dexpérience subjectif</h3>
<p><em>pieds nus</em> (code machine, ASM)</p>
<div class="incremental">
<pre><code> _
/ \
/. ) _
___/ | / / \
.-&#39;__/ |( ( .\
\ | \___
)| \__`-.
</code></pre>
<p><em>Talons hauts</em> (C, Pascal, Java, C++, Perl, PHP, Python, Ruby, etc…)</p>
</div>
<div class="incremental">
<p><em>Tennis</em> (Clojure, Scheme, LISP, etc…)</p>
</div>
<div class="incremental">
<p><em>Voiture</em> (Haskell, Purescript, etc…)</p>
</div>
<h2 id="pourquoi-haskell">Pourquoi Haskell?</h2>
<h3 id="simplicité-par-labstraction">Simplicité par labstraction</h3>
<p><strong><code>/!\</code> SIMPLICITÉ ≠ FACILITÉ <code>/!\</code></strong></p>
<ul>
<li>mémoire (garbage collection)</li>
<li>ordre dévaluation (non strict / lazy)</li>
<li>effets de bords (pur)</li>
<li>manipulation de code (referential transparency)</li>
</ul>
<h3 id="production-ready">Production Ready™</h3>
<ul>
<li>rapide
<ul>
<li>équivalent à Java (~ x2 du C)</li>
<li>parfois plus rapide que C</li>
<li>bien plus rapide que python et ruby</li>
</ul></li>
</ul>
<div class="incremental">
<ul>
<li>communauté solide
<ul>
<li>3k comptes sur Haskellers</li>
<li>&gt;30k sur reddit <em>(35k rust, 45k go, 50k nodejs, 4k ocaml, 13k clojure)</em></li>
<li>libs &gt;12k sur hackage</li>
</ul></li>
</ul>
</div>
<div class="incremental">
<ul>
<li>entreprises
<ul>
<li>Facebook (fighting spam, HAXL, …)</li>
<li>beaucoup de startups, finance en général</li>
</ul></li>
</ul>
</div>
<div class="incremental">
<ul>
<li>milieu académique
<ul>
<li>fondations mathématiques</li>
<li>fortes influences des chercheurs</li>
<li>tire le langage vers le haut</li>
</ul></li>
</ul>
</div>
<h3 id="tooling">Tooling</h3>
<ul>
<li>compilateur (GHC)</li>
<li>gestion de projets ; cabal, stack, hpack, etc…</li>
<li>IDE / hlint ; rapidité des erreurs en cours de frappe</li>
<li>frameworks hors catégorie (servant, yesod)</li>
<li>ecosystèmes très matures et inovant
<ul>
<li>Elm (⇒ frontend)</li>
<li>Purescript (⇒ frontend)</li>
<li>GHCJS (⇒ frontend)</li>
<li>Idris (types dépendants)</li>
<li>Hackett (typed LISP avec macros)</li>
</ul></li>
</ul>
<h3 id="qualité">Qualité</h3>
<blockquote>
<p><em>Si ça compile alors il probable que ça marche</em></p>
</blockquote>
<div class="incremental">
<ul>
<li>test unitaires : chercher quelques erreurs manuellements</li>
</ul>
</div>
<div class="incremental">
<ul>
<li><em>test génératifs</em> : chercher des erreurs sur beaucoups de cas générés aléatoirement &amp; aide pour trouver lerreur sur lobjet le plus simple</li>
</ul>
</div>
<div class="incremental">
<ul>
<li><em>finite state machine generative testing</em> : chercher des erreurs sur le déroulement des actions entre différents agents indépendants</li>
</ul>
</div>
<div class="incremental">
<ul>
<li><strong>preuves</strong>: chercher des erreur sur <strong>TOUTES</strong> les entrées possibles possible à laide du système de typage</li>
</ul>
</div>
<h1 id="premiers-pas-en-haskell">Premiers Pas en Haskell</h1>
<h3 id="hello-world-13">Hello World! (1/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> putStrLn <span class="st">&quot;Hello World!&quot;</span></code></pre></div>
<p><a href="~/.deft/pres-haskell/hello.hs">file:~/.deft/pres-haskell/hello.hs</a></p>
<h3 id="hello-world-23">Hello World! (2/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> putStrLn <span class="st">&quot;Hello World!&quot;</span></code></pre></div>
<ul>
<li><code>::</code> de type ;</li>
<li><code>=</code> égalité (la vrai, on peut interchanger ce quil y a des deux cotés) ;</li>
<li>le type de <code>putStrLn</code> est <code>String -&gt; IO ()</code> ;</li>
<li>le type de <code>main</code> est <code>IO ()</code>.</li>
</ul>
<h3 id="hello-world-33">Hello World! (3/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> putStrLn <span class="st">&quot;Hello World!&quot;</span></code></pre></div>
<ul>
<li>Le type <code>IO a</code> signifie: Cest une description dune procédure qui quand elle est évaluée peut faire des actions dIO et finalement retourne une valeur de type <code>a</code> ;</li>
<li><code>main</code> est le nom du point dentrée du programme ;</li>
<li>Haskell runtime va chercher pour <code>main</code> et lexécute.</li>
</ul>
<h2 id="what-is-your-name">What is your name?</h2>
<h3 id="what-is-your-name-13">What is your name? (1/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span>
putStrLn output</code></pre></div>
<p><a href="file:pres-haskell/name.hs" class="uri">file:pres-haskell/name.hs</a></p>
<h3 id="what-is-your-name-23">What is your name? (2/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span>
putStrLn output</code></pre></div>
<ul>
<li>lindentation est importante !</li>
<li><code>do</code> commence une syntaxe spéciale qui permet de séquencer des actions <code>IO</code> ;</li>
<li>le type de <code>getLine</code> est <code>IO String</code> ;</li>
<li><code>IO String</code> signifie: Ceci est la description dune procédure qui lorsquelle est évaluée peut faire des actions IO et à la fin retourne une valeur de type <code>String</code>.</li>
</ul>
<h3 id="what-is-your-name-33">What is your name? (3/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span>
putStrLn output</code></pre></div>
<ul>
<li>le type de <code>getLine</code> est <code>IO String</code></li>
<li>le type de <code>name</code> est <code>String</code></li>
<li><code>&lt;-</code> est une syntaxe spéciale qui napparait que dans la notation <code>do</code></li>
<li><code>&lt;-</code> signifie: évalue la procédure et attache la valeur renvoyée dans le nom à gauche de <code>&lt;-</code></li>
<li><code>let &lt;name&gt; = &lt;expr&gt;</code> signifie que <code>name</code> est interchangeable avec <code>expr</code> pour le reste du bloc <code>do</code>.</li>
<li>dans un bloc <code>do</code>, <code>let</code> na pas besoin dêtre accompagné par <code>in</code> à la fin.</li>
</ul>
<h2 id="erreurs-classiques">Erreurs classiques</h2>
<h3 id="erreur-classique-1">Erreur classique #1</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> getLine <span class="fu">++</span> <span class="st">&quot;!&quot;</span>
putStrLn output</code></pre></div>
<pre><code>/Users/yaesposi/.deft/pres-haskell/name.hs:6:40: warning: [-Wdeferred-type-errors]
• Couldn&#39;t match expected type [Char]
with actual type IO String
• In the first argument of (++), namely getLine
In the second argument of (++), namely getLine ++ &quot;!&quot;
In the expression: &quot;Nice to meet you, &quot; ++ getLine ++ &quot;!&quot;
|
6 | let output = &quot;Nice to meet you, &quot; ++ getLine ++ &quot;!&quot;
| ^^^^^^^
Ok, one module loaded.
</code></pre>
<h3 id="erreur-classique-1-1">Erreur classique #1</h3>
<ul>
<li><code>String</code> est <code>[Char]</code></li>
<li>Haskell narrive pas à faire matcher le type <code>String</code> avec <code>IO String</code>.</li>
<li><code>IO a</code> et <code>a</code> sont différents</li>
</ul>
<h3 id="erreur-classique-2">Erreur classique #2</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
putStrLn <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span></code></pre></div>
<pre><code>/Users/yaesposi/.deft/pres-haskell/name.hs:7:3: warning: [-Wdeferred-type-errors]
• Couldn&#39;t match expected type [Char] with actual type IO ()
• In the first argument of (++), namely
putStrLn &quot;Nice to meet you, &quot;
In a stmt of a &#39;do&#39; block:
putStrLn &quot;Nice to meet you, &quot; ++ name ++ &quot;!&quot;
In the expression:
do putStrLn &quot;Hello! What is your name?&quot;
name &lt;- getLine
putStrLn &quot;Nice to meet you, &quot; ++ name ++ &quot;!&quot;
|
7 | putStrLn &quot;Nice to meet you, &quot; ++ name ++ &quot;!&quot;
</code></pre>
<h3 id="erreur-classique-2-fix">Erreur classique #2 (fix)</h3>
<ul>
<li>Des parenthèses sont nécessaires</li>
<li>Lapplication de fonction se fait de gauche à droite</li>
</ul>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
putStrLn (<span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span>)</code></pre></div>
<h1 id="concepts-avec-exemples">Concepts avec exemples</h1>
<h3 id="concepts">Concepts</h3>
<ul>
<li><em>pureté</em> (par défaut)</li>
<li><em>evaluation paraisseuse</em> (par défaut)</li>
<li><em>ADT &amp; typage polymorphique</em></li>
</ul>
<h3 id="pureté-function-vs-proceduresubroutines"><em>Pureté</em>: Function vs Procedure/Subroutines</h3>
<ul>
<li>Une <em>fonction</em> na pas deffet de bord</li>
<li>Une <em>Procedure</em> ou <em>subroutine</em> but engendrer des effets de bords lors de son évaluation</li>
</ul>
<h3 id="pureté-function-vs-proceduresubroutines-exemple"><em>Pureté</em>: Function vs Procedure/Subroutines (exemple)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">dist ::</span> <span class="dt">Double</span> <span class="ot">-&gt;</span> <span class="dt">Double</span> <span class="ot">-&gt;</span> <span class="dt">Double</span>
dist x y <span class="fu">=</span> sqrt (x<span class="fu">**</span><span class="dv">2</span> <span class="fu">+</span> y<span class="fu">**</span><span class="dv">2</span>)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">getName ::</span> <span class="dt">IO</span> <span class="dt">String</span>
getName <span class="fu">=</span> readLine</code></pre></div>
<ul>
<li><strong>IO a</strong><strong>IMPUR</strong> ; effets de bords hors evaluation :
<ul>
<li>lire un fichier ;</li>
<li>écrire sur le terminal ;</li>
<li>changer la valeur dune variable en RAM est impur.</li>
</ul></li>
</ul>
<h3 id="pureté-gain-paralellisation-gratuite"><em>Pureté</em>: Gain, paralellisation gratuite</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">import </span><span class="dt">Foreign.Lib</span> (f)
<span class="co">-- f :: Int -&gt; Int</span>
<span class="co">-- f = ???</span>
foo <span class="fu">=</span> sum results
<span class="kw">where</span> results <span class="fu">=</span> map f [<span class="dv">1</span><span class="fu">..</span><span class="dv">100</span>]</code></pre></div>
<div class="incremental">
<p><strong><code>fmap</code> FTW!!!!! Assurance davoir le même résultat avec 32 cœurs</strong></p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">import </span><span class="dt">Foreign.Lib</span> (f)
<span class="co">-- f :: Int -&gt; Int</span>
<span class="co">-- f = ???</span>
foo <span class="fu">=</span> sum results
<span class="kw">where</span> results <span class="fu">=</span> fmap f [<span class="dv">1</span><span class="fu">..</span><span class="dv">100</span>]</code></pre></div>
</div>
<h3 id="pureté-structures-de-données-immuable"><em>Pureté</em>: Structures de données immuable</h3>
<p>Purely functional data structures, <em>Chris Okasaki</em></p>
<p>Thèse en 1996, et un livre.</p>
<p>Opérations sur les listes, tableaux, arbres de complexité amortie equivalent ou proche (pire des cas facteur log(n)) de celle des structures de données muables.</p>
<h3 id="évaluation-parraisseuse-stratégies-dévaluations"><em>Évaluation parraisseuse</em>: Stratégies dévaluations</h3>
<p><code>(h (f a) (g b))</code> peut sévaluer:</p>
<ul>
<li><code>a</code><code>(f a)</code><code>b</code><code>(g b)</code><code>(h (f a) (g b))</code></li>
<li><code>b</code><code>a</code><code>(g b)</code><code>(f a)</code><code>(h (f a) (g b))</code></li>
<li><code>a</code> et <code>b</code> en parallèle puis <code>(f a)</code> et <code>(g b)</code> en parallèle et finallement <code>(h (f a) (g b))</code></li>
<li><code>h</code><code>(f a)</code> seulement si nécessaire et puis <code>(g b)</code> seulement si nécessaire</li>
</ul>
<p>Par exemple: <code>(def h (λx.λy.(+ x x)))</code> il nest pas nécessaire dévaluer <code>y</code>, dans notre cas <code>(g b)</code></p>
<h3 id="évaluation-parraisseuse-exemple-1"><em>Évaluation parraisseuse</em>: Exemple 1</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">quickSort [] <span class="fu">=</span> []
quickSort (x<span class="fu">:</span>xs) <span class="fu">=</span> quickSort (filter (<span class="fu">&lt;</span>x) xs)
<span class="fu">++</span> [x]
<span class="fu">++</span> quickSort (filter (<span class="fu">&gt;=</span>x) xs)
minimum list <span class="fu">=</span> head (quickSort list)</code></pre></div>
<p>Un appel à <code>minimum longList</code> ne vas pas ordonner toute la liste. Le travail sarrêtera dès que le premier élément de la liste ordonnée sera trouvé.</p>
<p><code>take k (quickSort list)</code> est en <code>O(n + k log k)</code><code>n = length list</code>. Alors quavec une évaluation stricte: <code>O(n log n)</code>.</p>
<h3 id="évaluation-parraisseuse-structures-de-données-infinies-zip"><em>Évaluation parraisseuse</em>: Structures de données infinies (zip)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">zip<span class="ot"> ::</span> [a] <span class="ot">-&gt;</span> [b] <span class="ot">-&gt;</span> [(a,b)]
zip [] _ <span class="fu">=</span> []
zip _ [] <span class="fu">=</span> []
zip (x<span class="fu">:</span>xs) (y<span class="fu">:</span>ys) <span class="fu">=</span> (x,y)<span class="fu">:</span>zip xs ys</code></pre></div>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">zip [<span class="dv">1</span><span class="fu">..</span>] [<span class="ch">&#39;a&#39;</span>,<span class="ch">&#39;b&#39;</span>,<span class="ch">&#39;c&#39;</span>]</code></pre></div>
<p>sarrête et renvoie :</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">[(<span class="dv">1</span>,<span class="ch">&#39;a&#39;</span>), (<span class="dv">2</span>,<span class="ch">&#39;b&#39;</span>), (<span class="dv">3</span>, <span class="ch">&#39;c&#39;</span>)]</code></pre></div>
<h3 id="adt-typage-polymorphique"><em>ADT &amp; Typage polymorphique</em></h3>
<p>Algebraic Data Types.</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Void</span> <span class="fu">=</span> <span class="dt">Void</span> <span class="dt">Void</span> <span class="co">-- 0 valeur possible!</span>
<span class="kw">data</span> <span class="dt">Unit</span> <span class="fu">=</span> () <span class="co">-- 1 seule valeur possible</span>
<span class="kw">data</span> <span class="dt">Product</span> x y <span class="fu">=</span> <span class="dt">P</span> x y
<span class="kw">data</span> <span class="dt">Sum</span> x y <span class="fu">=</span> <span class="dt">S1</span> x <span class="fu">|</span> <span class="dt">S2</span> y</code></pre></div>
<p>Soit <code>#x</code> le nombre de valeurs possibles pour le type <code>x</code> alors:</p>
<ul>
<li><code>#(Product x y) = #x * #y</code></li>
<li><code>#(Sum x y) = #x + #y</code></li>
</ul>
<h3 id="adt-typage-polymorphique-inférence-de-type"><em>ADT &amp; Typage polymorphique</em>: Inférence de type</h3>
<p>À partir de :</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">zip [] _ <span class="fu">=</span> []
zip _ [] <span class="fu">=</span> []
zip (x<span class="fu">:</span>xs) (y<span class="fu">:</span>ys) <span class="fu">=</span> (x,y)<span class="fu">:</span>zip xs ys</code></pre></div>
<p>le compilateur peut déduire:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">zip<span class="ot"> ::</span> [a] <span class="ot">-&gt;</span> [b] <span class="ot">-&gt;</span> [(a,b)]</code></pre></div>
<h2 id="composabilité">Composabilité</h2>
<h3 id="composabilité-vs-modularité">Composabilité vs Modularité</h3>
<p>Modularité: soit un <code>a</code> et un <code>b</code>, je peux faire un <code>c</code>. ex: x un graphique, y une barre de menu =&gt; une page <code>let page = mkPage ( graphique, menu )</code></p>
<p>Composabilité: soit deux <code>a</code> je peux faire un autre <code>a</code>. ex: x un widget, y un widget =&gt; un widget <code>let page = x &lt;+&gt; y</code></p>
<p>Gain dabstraction, moindre coût.</p>
<p><strong>Hypothèses fortes sur les <code>a</code></strong></p>
<h3 id="exemples">Exemples</h3>
<ul>
<li><strong>Semi-groupes</strong> 〈+〉</li>
<li><p><strong>Monoides</strong> 〈0,+〉</p></li>
<li><strong>Catégories</strong> 〈obj(C),hom(C),∘〉</li>
<li>Foncteurs <code>fmap</code> (<code>(&lt;$&gt;)</code>)</li>
<li>Foncteurs Applicatifs <code>ap</code> (<code>(&lt;*&gt;)</code>)</li>
<li>Monades <code>join</code></li>
<li>Traversables <code>map</code></li>
<li><p>Foldables <code>reduce</code></p></li>
</ul>
<h1 id="catégories-de-bugs-évités-avec-haskell">Catégories de bugs évités avec Haskell</h1>
<h3 id="real-productions-bugs">Real Productions Bugs™</h3>
<p>Bug vu des dizaines de fois en prod malgré:</p>
<ol>
<li>specifications fonctionnelles</li>
<li>spécifications techniques</li>
<li>tests unitaires</li>
<li>3 envs, dev, recette/staging/pre-prod, prod</li>
<li>Équipe de QA qui teste en recette</li>
</ol>
<p>Solutions simples.</p>
<h3 id="null-pointer-exception-erreur-classique-1">Null Pointer Exception: Erreur classique (1)</h3>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">int <span class="at">foo</span>( x ) <span class="op">{</span>
<span class="cf">return</span> x <span class="op">+</span> <span class="dv">1</span><span class="op">;</span>
<span class="op">}</span></code></pre></div>
<h3 id="null-pointer-exception-erreur-classique-2">Null Pointer Exception: Erreur classique (2)</h3>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">int <span class="at">foo</span>( x ) <span class="op">{</span>
...
<span class="kw">var</span> y <span class="op">=</span> <span class="at">do_shit_1</span>(x)<span class="op">;</span>
...
<span class="cf">return</span> <span class="at">do_shit_20</span>(x)
<span class="op">}</span>
...
<span class="kw">var</span> val <span class="op">=</span> <span class="at">foo</span>(<span class="dv">26</span>/<span class="dv">2334</span> <span class="op">-</span> <span class="va">Math</span>.<span class="at">sqrt</span>(<span class="dv">2</span>))<span class="op">;</span></code></pre></div>
<div class="incremental">
<pre><code>888888b. .d88888b. 888 888 888b d888 888 888 888 888 888
888 &quot;88b d88P&quot; &quot;Y88b 888 888 8888b d8888 888 888 888 888 888
888 .88P 888 888 888 888 88888b.d88888 888 888 888 888 888
8888888K. 888 888 888 888 888Y88888P888 888 888 888 888 888
888 &quot;Y88b 888 888 888 888 888 Y888P 888 888 888 888 888 888
888 888 888 888 888 888 888 Y8P 888 Y8P Y8P Y8P Y8P Y8P
888 d88P Y88b. .d88P Y88b. .d88P 888 &quot; 888 &quot; &quot; &quot; &quot; &quot;
8888888P&quot; &quot;Y88888P&quot; &quot;Y88888P&quot; 888 888 888 888 888 888 888
</code></pre>
<p><strong>Null Pointer Exception</strong></p>
</div>
<h3 id="null-pointer-exception-data-type-maybe">Null Pointer Exception: Data type <code>Maybe</code></h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Maybe</span> a <span class="fu">=</span> <span class="dt">Just</span> a <span class="fu">|</span> <span class="dt">Nothing</span>
<span class="fu">...</span>
<span class="ot">foo ::</span> <span class="dt">Maybe</span> a
<span class="fu">...</span>
myFunc x <span class="fu">=</span> <span class="kw">let</span> t <span class="fu">=</span> foo x <span class="kw">in</span>
<span class="kw">case</span> t <span class="kw">of</span>
<span class="dt">Just</span> someValue <span class="ot">-&gt;</span> doThingsWith someValue
<span class="dt">Nothing</span> <span class="ot">-&gt;</span> doThingWhenNothingIsReturned</code></pre></div>
<p>Le compilateur oblige à tenir compte des cas particuliers! Impossible doublier.</p>
<h3 id="null-pointer-excepton-etat">Null Pointer Excepton: Etat</h3>
<ul>
<li>Rendre impossibe de fabriquer un état qui devrait être impossible davoir.</li>
<li>Pour aller plus loin voir, FRP, CQRS/ES, Elm-architecture, etc…</li>
</ul>
<h3 id="erreur-due-à-une-typo">Erreur due à une typo</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Foo</span> x <span class="fu">=</span> <span class="dt">LongNameWithPossibleError</span> x
<span class="fu">...</span>
foo (<span class="dt">LongNameWithPosibleError</span> x) <span class="fu">=</span> <span class="fu">...</span></code></pre></div>
<p><strong>Erreur à la compilation</strong>: Le nom dun champ nest pas une string (voir les objets JSON).</p>
<h3 id="echange-de-parameters">Echange de parameters</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Personne</span> <span class="fu">=</span> <span class="dt">Personne</span> {<span class="ot"> uid ::</span> <span class="dt">Int</span>,<span class="ot"> age ::</span> <span class="dt">Int</span> }
<span class="ot">foo ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Personne</span> <span class="co">-- ??? uid ou age?</span></code></pre></div>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">newtype</span> <span class="dt">UID</span> <span class="fu">=</span> <span class="dt">UID</span> <span class="dt">Int</span> <span class="kw">deriving</span> (<span class="dt">Eq</span>)
<span class="kw">data</span> <span class="dt">Personne</span> <span class="fu">=</span> <span class="dt">Personne</span> {<span class="ot"> uid ::</span> <span class="dt">UID</span>,<span class="ot"> age ::</span> <span class="dt">Int</span> }
<span class="ot">foo ::</span> <span class="dt">UDI</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Personne</span> <span class="co">-- Impossible de confondre</span></code></pre></div>
<h3 id="changement-intempestif-dun-etat-global">Changement intempestif dun Etat Global</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">foo ::</span> <span class="dt">GlobalState</span> <span class="ot">-&gt;</span> x</code></pre></div>
<p><strong><code>foo</code> ne peut pas changer <code>GlobalState</code></strong></p>
<h1 id="organisation-du-code">Organisation du Code</h1>
<h3 id="grands-concepts">Grands Concepts</h3>
<p>Procedure vs Functions:</p>
<table>
<tbody>
<tr class="odd">
<td>Gestion dune configuration globale</td>
</tr>
<tr class="even">
<td>Gestion dun état global</td>
</tr>
<tr class="odd">
<td>Gestion des Erreurs</td>
</tr>
<tr class="even">
<td>Gestion des IO</td>
</tr>
</tbody>
</table>
<h3 id="monades">Monades</h3>
<p>Pour chacun de ces <em>problèmes</em> il existe une monade:</p>
<table>
<tbody>
<tr class="odd">
<td>Gestion dune configuration globale</td>
<td><code>Reader</code></td>
</tr>
<tr class="even">
<td>Gestion dun état global</td>
<td><code>State</code></td>
</tr>
<tr class="odd">
<td>Gestion des Erreurs</td>
<td><code>Either</code></td>
</tr>
<tr class="even">
<td>Gestion des IO</td>
<td><code>IO</code></td>
</tr>
</tbody>
</table>
<h3 id="effets">Effets</h3>
<p>Gestion de plusieurs Effets dans la même fonction:</p>
<ul>
<li>MTL</li>
<li>Free Monad</li>
<li>Freer Monad</li>
</ul>
<p>Idée: donner à certaines sous-fonction accès à une partie des effets seulement.</p>
<p>Par exemple:</p>
<ul>
<li>limiter une fonction à la lecture de la DB mais pas lécriture.</li>
<li>limiter lécriture à une seule table</li>
<li>interdire lécriture de logs</li>
<li>interdire lécriture sur le disque dur</li>
<li>etc…</li>
</ul>
<h3 id="exemple-dans-un-code-réel-1">Exemple dans un code réel (1)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="co">-- | ConsumerBot type, the main monad in which the bot code is written with.</span>
<span class="co">-- Provide config, state, logs and IO</span>
<span class="kw">type</span> <span class="dt">ConsumerBot</span> m a <span class="fu">=</span>
( <span class="dt">MonadState</span> <span class="dt">ConsumerState</span> m
, <span class="dt">MonadReader</span> <span class="dt">ConsumerConf</span> m
, <span class="dt">MonadLog</span> (<span class="dt">WithSeverity</span> <span class="dt">Doc</span>) m
, <span class="dt">MonadBaseControl</span> <span class="dt">IO</span> m
, <span class="dt">MonadSleep</span> m
, <span class="dt">MonadPubSub</span> m
, <span class="dt">MonadIO</span> m
) <span class="ot">=&gt;</span> m a</code></pre></div>
<h3 id="exemple-dans-un-code-réel-2">Exemple dans un code réel (2)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">bot ::</span> <span class="dt">Manager</span>
<span class="ot">-&gt;</span> <span class="dt">RotatingLog</span>
<span class="ot">-&gt;</span> <span class="dt">Chan</span> <span class="dt">RedditComment</span>
<span class="ot">-&gt;</span> <span class="dt">TVar</span> <span class="dt">RedbotConfs</span>
<span class="ot">-&gt;</span> <span class="dt">Severity</span>
<span class="ot">-&gt;</span> <span class="dt">IO</span> ()
bot manager rotLog pubsub redbots minSeverity <span class="fu">=</span> <span class="kw">do</span>
TC.setDefaultPersist TC.filePersist
<span class="kw">let</span> conf <span class="fu">=</span> <span class="dt">ConsumerConf</span>
{ rhconf <span class="fu">=</span> <span class="dt">RedditHttpConf</span> { _connMgr <span class="fu">=</span> manager }
, commentStream <span class="fu">=</span> pubsub
}
void <span class="fu">$</span> autobot
<span class="fu">&amp;</span> flip runReaderT conf
<span class="fu">&amp;</span> flip runStateT (initState redbots)
<span class="fu">&amp;</span> flip runLoggingT (renderLog minSeverity rotLog)</code></pre></div>
<h2 id="règles-pragmatiques">Règles <strong>pragmatiques</strong></h2>
<h3 id="organisation-en-fonction-de-la-complexité">Organisation en fonction de la complexité</h3>
<blockquote>
<p>Make it work, make it right, make it fast</p>
</blockquote>
<ul>
<li>Simple: directement IO (YOLO!)</li>
<li>Medium: Haskell Design Patterns: The Handle Pattern: <a href="https://jaspervdj.be/posts/2018-03-08-handle-pattern.html" class="uri">https://jaspervdj.be/posts/2018-03-08-handle-pattern.html</a></li>
<li>Medium (bis): MTL / Free / Freeer / Effects…</li>
<li>Gros: Three Layer Haskell Cake: <a href="http://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html" class="uri">http://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html</a>
<ul>
<li>Layer 1: Imperatif</li>
<li>Orienté Objet (Level 2 / 2)</li>
<li>Fonctionnel</li>
</ul></li>
</ul>
<h3 id="couches">3 couches</h3>
<ul>
<li><strong>Imperatif</strong>: ReaderT IO
<ul>
<li>Insérer létat dans une <code>TVar</code>, <code>MVar</code> ou <code>IORef</code> (concurrence)</li>
</ul></li>
<li><strong>Orienté Objet</strong>:
<ul>
<li>Handle / MTL / Free…</li>
<li>donner des access <code>UserDB</code>, <code>AccessTime</code>, <code>APIHTTP</code></li>
</ul></li>
<li><strong>Fonctionnel</strong>: Business Logic <code>f : Handlers -&gt; Inputs -&gt; Command</code></li>
</ul>
<h3 id="services-lib">Services / Lib</h3>
<p>Service: <code>init</code> / <code>start</code> / <code>close</code> + methodes… Lib: methodes sans état interne.</p>
<h1 id="conclusion">Conclusion</h1>
<h3 id="pourquoi-haskell-1">Pourquoi Haskell?</h3>
<ul>
<li>avantage compétitif: qualité x productivité hors norme</li>
<li>changera son approche de la programmation</li>
<li>les concepts appris sont utilisables dans tous les languages</li>
<li>permet daller là où aucun autre langage ne peut vous amener</li>
<li>Approfondissement sans fin:
<ul>
<li>Théorie: théorie des catégories, théorie des types homotopiques, etc…</li>
<li>Optim: compilateur</li>
<li>Qualité: tests, preuves</li>
<li>Organisation: capacité de contraindre de très haut vers très bas</li>
</ul></li>
</ul>
<h3 id="avantage-compétitif">Avantage compétitif</h3>
<ul>
<li>France, Europe du sud &amp; Functional Programming</li>
<li>Maintenance &gt;&gt; production dun nouveau produit</li>
<li>Coût de la refactorisation</li>
<li>“Make it work, Make it right, Make it fast” moins cher.</li>
</ul>
<h1 id="appendix">Appendix</h1>
<h3 id="stm-exemple-concurrence-12">STM: Exemple (Concurrence) (1/2)</h3>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java"><span class="kw">class</span> Account {
<span class="dt">float</span> balance;
<span class="kw">synchronized</span> <span class="dt">void</span> <span class="fu">deposit</span>(<span class="dt">float</span> amount){
balance += amount; }
<span class="kw">synchronized</span> <span class="dt">void</span> <span class="fu">withdraw</span>(<span class="dt">float</span> amount){
<span class="kw">if</span> (balance &lt; amount) <span class="kw">throw</span> <span class="kw">new</span> <span class="fu">OutOfMoneyError</span>();
balance -= amount; }
<span class="kw">synchronized</span> <span class="dt">void</span> <span class="fu">transfert</span>(Account other, <span class="dt">float</span> amount){
other.<span class="fu">withdraw</span>(amount);
<span class="kw">this</span>.<span class="fu">deposit</span>(amount); }
}</code></pre></div>
<p>Situation dinterblocage typique. (A transfert vers B et B vers A).</p>
<h3 id="stm-exemple-concurrence-22">STM: Exemple (Concurrence) (2/2)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">deposit ::</span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> ()
deposit acc n <span class="fu">=</span> <span class="kw">do</span>
bal <span class="ot">&lt;-</span> readTVar acc
writeTVar acc (bal <span class="fu">+</span> n)
<span class="ot">withdraw ::</span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> ()
withdraw acc n <span class="fu">=</span> <span class="kw">do</span>
bal <span class="ot">&lt;-</span> readTVar acc
<span class="kw">if</span> bal <span class="fu">&lt;</span> n <span class="kw">then</span> retry
writeTVar acc (bal <span class="fu">-</span> n)
<span class="ot">transfer ::</span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> ()
transfer from to n <span class="fu">=</span> <span class="kw">do</span>
withdraw from n
deposit to n</code></pre></div>
<ul>
<li>pas de lock explicite, composition naturelle dans <code>transfer</code>.</li>
<li>si une des deux opération échoue toute la transaction échoue</li>
<li>le système de type force cette opération a être atomique: <code>atomically :: STM a -&gt; IO a</code></li>
</ul>
<div id="footer">
<a href="http://yannesposito.com">yannesposito.com</a>
Proudly generated by <a href="http://github.com/yogsototh/mkdocs">mkdocs</a>
</div>
</body>
</html>

847
pres-Haskell-Intro.org Normal file
View file

@ -0,0 +1,847 @@
#+Title: Introduction à la Programmation Fonctionnelle en Haskell
#+Author: Yann Esposito
#+Date: <2018-03-15 Thu>
* Courte Introduction
** Prelude
Initialiser l'env de dev:
#+BEGIN_SRC shell
curl -sSL https://get.haskellstack.org/ | sh
stack new ipfh https://git.io/vbpej && \
cd ipfh && \
stack setup && \
stack build && \
stack test && \
stack bench
#+END_SRC
** Parcours jusqu'à Haskell
*** Parcours Pro
- Doctorat (machine learning, hidden markov models) 2004
- Post doc (écriture d'un UI pour des biologistes en Java). 2006
- Dev Airfrance, (Perl, scripts shell, awk, HTML, CSS, JS, XML...) 2006 → 2013
- Dev (ruby, C, ML) pour GridPocket. (dev) 2009 → 2011, (impliqué) 2009 →
- Clojure dev & Machine Learning pour Vigiglobe. 2013 → 2016
- Senior Clojure développeur chez Cisco. 2016 →
*** Langages de programmations basiques
1. BASIC (MO5, Amstrad CPC 6129, Atari STf)
2. Logo (école primaire, + écriture d'un cours en 1ère année de Fac)
3. Pascal (lycée, fac)
4. C (fac)
5. ADA (fac)
*** Langages de programmations orientés objet
6. C++ (fac + outils de recherche pour doctorat)
7. Eiffel (fac)
8. Java (fac, UI en Java 1.6, Swing pour postdoc)
9. Objective-C (temps personnel, app iPhone, app Mac, Screensavers)
*** Langages moderne de script
10. PHP (fac, site perso)
11. Python (fac, projets perso, jeux, etc...)
12. Awk (fac, Airfrance, ...)
13. Perl (Airfrance...)
14. Ruby (GridPocket, site perso v2)
15. Javascript:
- /Airfrance/ basic prototype, jquery, etc..,
- spine.js
- backbone.js
- Coffeescript
- Cappuccino (Objective-J)
- Sproutcore
- /Vigiglobe/ actionhero (nodejs), angularjs v1
*** Langage peu (re)connus
18. Metapost
19. zsh (quasi lang de prog)
20. prolog
*** Langages fonctionnels
16. CamL
17. Haskell (Vigiglobe, personnal)
18. Clojure (Vigiglobe, Cisco)
** Qu'est-ce que la programmation fonctionnelle?
*** Von Neumann Architecture
#+BEGIN_SRC
+--------------------------------+
| +----------------------------+ |
| | central processing unit | |
| | +------------------------+ | |
| | | Control Unit | | |
+------+ | | +------------------------+ | | +--------+
|input +---> | +------------------------+ | +--> output |
+------+ | | | Arithmetic/Logic Unit | | | +--------+
| | +------------------------+ | |
| +-------+---^----------------+ |
| | | |
| +-------v---+----------------+ |
| | Memory Unit | |
| +----------------------------+ |
+--------------------------------+
#+END_SRC
made with http://asciiflow.com
*** Von Neumann vs Church
- programmer à partir de la machine (Von Neumann)
+ tire vers l'optimisation
+ mots de bits, caches, détails de bas niveau
+ actions séquentielles
+ *1 siècle d'expérience*
. . .
- programmer comme manipulation de symbole (Alonzo Church)
+ tire vers l'abstraction
+ plus proche des représentations mathématiques
+ ordre d'évaluation non imposé
+ *4000 ans d'expérience*
*** Histoire
- λ-Calculus, Alonzo Church & Rosser 1936
- Foundation, explicit side effect no implicit state
. . .
- LISP (McCarthy 1960)
- Garbage collection, higher order functions, dynamic typing
. . .
- ML (1969-80)
- Static typing, Algebraic Datatypes, Pattern matching
. . .
- Miranda (1986) → Haskell (1992‥)
- Lazy evaluation, pure
*** Retour d'expérience subjectif
/pieds nus/ (code machine, ASM)
. . .
#+BEGIN_SRC
_
/ \
/. ) _
___/ | / / \
.-'__/ |( ( .\
\ | \___
)| \__`-.
#+END_SRC
/Talons hauts/ (C, Pascal, Java, C++, Perl, PHP, Python, Ruby, etc...)
. . .
/Tennis/ (Clojure, Scheme, LISP, etc...)
. . .
/Voiture/ (Haskell, Purescript, etc...)
** Pourquoi Haskell?
*** Simplicité par l'abstraction
*=/!\= SIMPLICITÉ ≠ FACILITÉ =/!\=*
- mémoire (garbage collection)
- ordre d'évaluation (non strict / lazy)
- effets de bords (pur)
- manipulation de code (referential transparency)
*** Production Ready™
- rapide
- équivalent à Java (~ x2 du C)
- parfois plus rapide que C
- bien plus rapide que python et ruby
. . .
- communauté solide
- 3k comptes sur Haskellers
- >30k sur reddit /(35k rust, 45k go, 50k nodejs, 4k ocaml, 13k clojure)/
- libs >12k sur hackage
. . .
- entreprises
- Facebook (fighting spam, HAXL, ...)
- beaucoup de startups, finance en général
. . .
- milieu académique
- fondations mathématiques
- fortes influences des chercheurs
- tire le langage vers le haut
*** Tooling
- compilateur (GHC)
- gestion de projets ; cabal, stack, hpack, etc...
- IDE / hlint ; rapidité des erreurs en cours de frappe
- frameworks hors catégorie (servant, yesod)
- ecosystèmes très matures et inovant
- Elm (⇒ frontend)
- Purescript (⇒ frontend)
- GHCJS (⇒ frontend)
- Idris (types dépendants)
- Hackett (typed LISP avec macros)
*** Qualité
#+BEGIN_QUOTE
/Si ça compile alors il probable que ça marche/
#+END_QUOTE
. . .
- test unitaires :
chercher quelques erreurs manuellements
. . .
- /test génératifs/ :
chercher des erreurs sur beaucoups de cas générés aléatoirement
& aide pour trouver l'erreur sur l'objet le plus simple
. . .
- /finite state machine generative testing/ :
chercher des erreurs sur le déroulement des actions
entre différents agents indépendants
. . .
- *preuves*:
chercher des erreur sur *TOUTES* les entrées possibles
possible à l'aide du système de typage
* Premiers Pas en Haskell
*** Hello World! (1/3)
#+BEGIN_SRC haskell
module Main where
main :: IO ()
main = putStrLn "Hello World!"
#+END_SRC
[[file:~/.deft/pres-haskell/hello.hs]]
*** Hello World! (2/3)
#+BEGIN_SRC haskell
module Main where
main :: IO ()
main = putStrLn "Hello World!"
#+END_SRC
- ~::~ de type ;
- ~=~ égalité (la vrai, on peut interchanger ce qu'il y a des deux cotés) ;
- le type de ~putStrLn~ est ~String -> IO ()~ ;
- le type de ~main~ est ~IO ()~.
*** Hello World! (3/3)
#+BEGIN_SRC haskell
module Main where
main :: IO ()
main = putStrLn "Hello World!"
#+END_SRC
- Le type ~IO a~ signifie: C'est une description d'une procédure qui quand elle
est évaluée peut faire des actions d'IO et finalement retourne une valeur de
type ~a~ ;
- ~main~ est le nom du point d'entrée du programme ;
- Haskell runtime va chercher pour ~main~ et l'exécute.
** What is your name?
*** What is your name? (1/3)
#+BEGIN_SRC haskell
module Main where
main :: IO ()
main = do
putStrLn "Hello! What is your name?"
name <- getLine
let output = "Nice to meet you, " ++ name ++ "!"
putStrLn output
#+END_SRC
file:pres-haskell/name.hs
*** What is your name? (2/3)
#+BEGIN_SRC haskell
module Main where
main :: IO ()
main = do
putStrLn "Hello! What is your name?"
name <- getLine
let output = "Nice to meet you, " ++ name ++ "!"
putStrLn output
#+END_SRC
- l'indentation est importante !
- ~do~ commence une syntaxe spéciale qui permet de séquencer des actions ~IO~ ;
- le type de ~getLine~ est ~IO String~ ;
- ~IO String~ signifie: Ceci est la description d'une procédure qui lorsqu'elle
est évaluée peut faire des actions IO et à la fin retourne une valeur de type
~String~.
*** What is your name? (3/3)
#+BEGIN_SRC haskell
module Main where
main :: IO ()
main = do
putStrLn "Hello! What is your name?"
name <- getLine
let output = "Nice to meet you, " ++ name ++ "!"
putStrLn output
#+END_SRC
- le type de ~getLine~ est ~IO String~
- le type de ~name~ est ~String~
- ~<-~ est une syntaxe spéciale qui n'apparait que dans la notation ~do~
- ~<-~ signifie: évalue la procédure et attache la valeur renvoyée dans le nom
à gauche de ~<-~
- ~let <name> = <expr>~ signifie que ~name~ est interchangeable avec ~expr~ pour
le reste du bloc ~do~.
- dans un bloc ~do~, ~let~ n'a pas besoin d'être accompagné par ~in~ à la fin.
** Erreurs classiques
*** Erreur classique #1
#+BEGIN_SRC haskell
module Main where
main :: IO ()
main = do
putStrLn "Hello! What is your name?"
let output = "Nice to meet you, " ++ getLine ++ "!"
putStrLn output
#+END_SRC
#+BEGIN_SRC
/Users/yaesposi/.deft/pres-haskell/name.hs:6:40: warning: [-Wdeferred-type-errors]
• Couldn't match expected type [Char]
with actual type IO String
• In the first argument of (++), namely getLine
In the second argument of (++), namely getLine ++ "!"
In the expression: "Nice to meet you, " ++ getLine ++ "!"
|
6 | let output = "Nice to meet you, " ++ getLine ++ "!"
| ^^^^^^^
Ok, one module loaded.
#+END_SRC
*** Erreur classique #1
- ~String~ est ~[Char]~
- Haskell n'arrive pas à faire matcher le type ~String~ avec ~IO String~.
- ~IO a~ et ~a~ sont différents
*** Erreur classique #2
#+BEGIN_SRC haskell
module Main where
main :: IO ()
main = do
putStrLn "Hello! What is your name?"
name <- getLine
putStrLn "Nice to meet you, " ++ name ++ "!"
#+END_SRC
#+BEGIN_SRC
/Users/yaesposi/.deft/pres-haskell/name.hs:7:3: warning: [-Wdeferred-type-errors]
• Couldn't match expected type [Char] with actual type IO ()
• In the first argument of (++), namely
putStrLn "Nice to meet you, "
In a stmt of a 'do' block:
putStrLn "Nice to meet you, " ++ name ++ "!"
In the expression:
do putStrLn "Hello! What is your name?"
name <- getLine
putStrLn "Nice to meet you, " ++ name ++ "!"
|
7 | putStrLn "Nice to meet you, " ++ name ++ "!"
#+END_SRC
*** Erreur classique #2 (fix)
- Des parenthèses sont nécessaires
- L'application de fonction se fait de gauche à droite
#+BEGIN_SRC haskell
module Main where
main :: IO ()
main = do
putStrLn "Hello! What is your name?"
name <- getLine
putStrLn ("Nice to meet you, " ++ name ++ "!")
#+END_SRC
* Concepts avec exemples
*** Concepts
- /pureté/ (par défaut)
- /evaluation paraisseuse/ (par défaut)
- /ADT & typage polymorphique/
*** /Pureté/: Function vs Procedure/Subroutines
- Une /fonction/ n'a pas d'effet de bord
- Une /Procedure/ ou /subroutine/ but engendrer des effets de bords lors de son
évaluation
*** /Pureté/: Function vs Procedure/Subroutines (exemple)
#+BEGIN_SRC haskell
dist :: Double -> Double -> Double
dist x y = sqrt (x**2 + y**2)
#+END_SRC
#+BEGIN_SRC haskell
getName :: IO String
getName = readLine
#+END_SRC
- *IO a**IMPUR* ; effets de bords hors evaluation :
- lire un fichier ;
- écrire sur le terminal ;
- changer la valeur d'une variable en RAM est impur.
*** /Pureté/: Gain, paralellisation gratuite
#+BEGIN_SRC haskell
import Foreign.Lib (f)
-- f :: Int -> Int
-- f = ???
foo = sum results
where results = map f [1..100]
#+END_SRC
. . .
*~fmap~ FTW!!!!! Assurance d'avoir le même résultat avec 32 cœurs*
#+BEGIN_SRC haskell
import Foreign.Lib (f)
-- f :: Int -> Int
-- f = ???
foo = sum results
where results = fmap f [1..100]
#+END_SRC
*** /Pureté/: Structures de données immuable
Purely functional data structures,
/Chris Okasaki/
Thèse en 1996, et un livre.
Opérations sur les listes, tableaux, arbres
de complexité amortie equivalent ou proche
(pire des cas facteur log(n))
de celle des structures de données muables.
*** /Évaluation parraisseuse/: Stratégies d'évaluations
=(h (f a) (g b))= peut s'évaluer:
- =a==(f a)==b==(g b)==(h (f a) (g b))=
- =b==a==(g b)==(f a)==(h (f a) (g b))=
- =a= et =b= en parallèle puis =(f a)= et =(g b)= en parallèle et finallement
=(h (f a) (g b))=
- =h==(f a)= seulement si nécessaire et puis =(g b)= seulement si nécessaire
Par exemple: =(def h (λx.λy.(+ x x)))= il n'est pas nécessaire d'évaluer =y=,
dans notre cas =(g b)=
*** /Évaluation parraisseuse/: Exemple 1
#+BEGIN_SRC haskell
quickSort [] = []
quickSort (x:xs) = quickSort (filter (<x) xs)
++ [x]
++ quickSort (filter (>=x) xs)
minimum list = head (quickSort list)
#+END_SRC
Un appel à ~minimum longList~ ne vas pas ordonner toute la liste.
Le travail s'arrêtera dès que le premier élément de la liste ordonnée sera trouvé.
~take k (quickSort list)~ est en ~O(n + k log k)~~n = length list~.
Alors qu'avec une évaluation stricte: ~O(n log n)~.
*** /Évaluation parraisseuse/: Structures de données infinies (zip)
#+BEGIN_SRC haskell
zip :: [a] -> [b] -> [(a,b)]
zip [] _ = []
zip _ [] = []
zip (x:xs) (y:ys) = (x,y):zip xs ys
#+END_SRC
#+BEGIN_SRC haskell
zip [1..] ['a','b','c']
#+END_SRC
s'arrête et renvoie :
#+BEGIN_SRC haskell
[(1,'a'), (2,'b'), (3, 'c')]
#+END_SRC
*** /ADT & Typage polymorphique/
Algebraic Data Types.
#+BEGIN_SRC haskell
data Void = Void Void -- 0 valeur possible!
data Unit = () -- 1 seule valeur possible
data Product x y = P x y
data Sum x y = S1 x | S2 y
#+END_SRC
Soit ~#x~ le nombre de valeurs possibles pour le type ~x~
alors:
- ~#(Product x y) = #x * #y~
- ~#(Sum x y) = #x + #y~
*** /ADT & Typage polymorphique/: Inférence de type
À partir de :
#+BEGIN_SRC haskell
zip [] _ = []
zip _ [] = []
zip (x:xs) (y:ys) = (x,y):zip xs ys
#+END_SRC
le compilateur peut déduire:
#+BEGIN_SRC haskell
zip :: [a] -> [b] -> [(a,b)]
#+END_SRC
** Composabilité
*** Composabilité vs Modularité
Modularité: soit un ~a~ et un ~b~, je peux faire un ~c~.
ex: x un graphique, y une barre de menu => une page
~let page = mkPage ( graphique, menu )~
Composabilité: soit deux ~a~ je peux faire un autre ~a~.
ex: x un widget, y un widget => un widget
~let page = x <+> y~
Gain d'abstraction, moindre coût.
*Hypothèses fortes sur les ~a~*
*** Exemples
- *Semi-groupes* 〈+〉
- *Monoides* 〈0,+〉
- *Catégories* 〈obj(C),hom(C),∘〉
- Foncteurs ~fmap~ (~(<$>)~)
- Foncteurs Applicatifs ~ap~ (~(<*>)~)
- Monades ~join~
- Traversables ~map~
- Foldables ~reduce~
* Catégories de bugs évités avec Haskell
*** Real Productions Bugs™
Bug vu des dizaines de fois en prod malgré:
1. specifications fonctionnelles
2. spécifications techniques
3. tests unitaires
4. 3 envs, dev, recette/staging/pre-prod, prod
5. Équipe de QA qui teste en recette
Solutions simples.
*** Null Pointer Exception: Erreur classique (1)
#+BEGIN_SRC javascript
int foo( x ) {
return x + 1;
}
#+END_SRC
*** Null Pointer Exception: Erreur classique (2)
#+BEGIN_SRC javascript
int foo( x ) {
...
var y = do_shit_1(x);
...
return do_shit_20(x)
}
...
var val = foo(26/2334 - Math.sqrt(2));
#+END_SRC
. . .
#+BEGIN_SRC
888888b. .d88888b. 888 888 888b d888 888 888 888 888 888
888 "88b d88P" "Y88b 888 888 8888b d8888 888 888 888 888 888
888 .88P 888 888 888 888 88888b.d88888 888 888 888 888 888
8888888K. 888 888 888 888 888Y88888P888 888 888 888 888 888
888 "Y88b 888 888 888 888 888 Y888P 888 888 888 888 888 888
888 888 888 888 888 888 888 Y8P 888 Y8P Y8P Y8P Y8P Y8P
888 d88P Y88b. .d88P Y88b. .d88P 888 " 888 " " " " "
8888888P" "Y88888P" "Y88888P" 888 888 888 888 888 888 888
#+END_SRC
*Null Pointer Exception*
*** Null Pointer Exception: Data type ~Maybe~
#+BEGIN_SRC haskell
data Maybe a = Just a | Nothing
...
foo :: Maybe a
...
myFunc x = let t = foo x in
case t of
Just someValue -> doThingsWith someValue
Nothing -> doThingWhenNothingIsReturned
#+END_SRC
Le compilateur oblige à tenir compte des cas particuliers!
Impossible d'oublier.
*** Null Pointer Excepton: Etat
- Rendre impossibe de fabriquer un état qui devrait être impossible d'avoir.
- Pour aller plus loin voir, FRP, CQRS/ES, Elm-architecture, etc...
*** Erreur due à une typo
#+BEGIN_SRC haskell
data Foo x = LongNameWithPossibleError x
...
foo (LongNameWithPosibleError x) = ...
#+END_SRC
*Erreur à la compilation*:
Le nom d'un champ n'est pas une string
(voir les objets JSON).
*** Echange de parameters
#+BEGIN_SRC haskell
data Personne = Personne { uid :: Int, age :: Int }
foo :: Int -> Int -> Personne -- ??? uid ou age?
#+END_SRC
#+BEGIN_SRC haskell
newtype UID = UID Int deriving (Eq)
data Personne = Personne { uid :: UID, age :: Int }
foo :: UDI -> Int -> Personne -- Impossible de confondre
#+END_SRC
*** Changement intempestif d'un Etat Global
#+BEGIN_SRC haskell
foo :: GlobalState -> x
#+END_SRC
*~foo~ ne peut pas changer =GlobalState=*
* Organisation du Code
*** Grands Concepts
Procedure vs Functions:
| Gestion d'une configuration globale |
| Gestion d'un état global |
| Gestion des Erreurs |
| Gestion des IO |
*** Monades
Pour chacun de ces /problèmes/ il existe une monade:
| Gestion d'une configuration globale | ~Reader~ |
| Gestion d'un état global | ~State~ |
| Gestion des Erreurs | ~Either~ |
| Gestion des IO | ~IO~ |
*** Effets
Gestion de plusieurs Effets dans la même fonction:
- MTL
- Free Monad
- Freer Monad
Idée: donner à certaines sous-fonction accès à une partie des effets seulement.
Par exemple:
- limiter une fonction à la lecture de la DB mais pas l'écriture.
- limiter l'écriture à une seule table
- interdire l'écriture de logs
- interdire l'écriture sur le disque dur
- etc...
*** Exemple dans un code réel (1)
#+BEGIN_SRC haskell
-- | ConsumerBot type, the main monad in which the bot code is written with.
-- Provide config, state, logs and IO
type ConsumerBot m a =
( MonadState ConsumerState m
, MonadReader ConsumerConf m
, MonadLog (WithSeverity Doc) m
, MonadBaseControl IO m
, MonadSleep m
, MonadPubSub m
, MonadIO m
) => m a
#+END_SRC
*** Exemple dans un code réel (2)
#+BEGIN_SRC haskell
bot :: Manager
-> RotatingLog
-> Chan RedditComment
-> TVar RedbotConfs
-> Severity
-> IO ()
bot manager rotLog pubsub redbots minSeverity = do
TC.setDefaultPersist TC.filePersist
let conf = ConsumerConf
{ rhconf = RedditHttpConf { _connMgr = manager }
, commentStream = pubsub
}
void $ autobot
& flip runReaderT conf
& flip runStateT (initState redbots)
& flip runLoggingT (renderLog minSeverity rotLog)
#+END_SRC
** Règles *pragmatiques*
*** Organisation en fonction de la complexité
#+BEGIN_QUOTE
Make it work, make it right, make it fast
#+END_QUOTE
- Simple: directement IO (YOLO!)
- Medium: Haskell Design Patterns: The Handle Pattern:
https://jaspervdj.be/posts/2018-03-08-handle-pattern.html
- Medium (bis): MTL / Free / Freeer / Effects...
- Gros: Three Layer Haskell Cake:
http://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html
+ Layer 1: Imperatif
+ Orienté Objet (Level 2 / 2')
+ Fonctionnel
*** 3 couches
- *Imperatif*:
ReaderT IO
+ Insérer l'état dans une ~TVar~, ~MVar~ ou ~IORef~ (concurrence)
- *Orienté Objet*:
+ Handle / MTL / Free...
+ donner des access ~UserDB~, ~AccessTime~, ~APIHTTP~...
- *Fonctionnel*: Business Logic ~f : Handlers -> Inputs -> Command~
*** Services / Lib
Service: ~init~ / ~start~ / ~close~ + methodes...
Lib: methodes sans état interne.
* Conclusion
*** Pourquoi Haskell?
- avantage compétitif: qualité x productivité hors norme
- changera son approche de la programmation
- les concepts appris sont utilisables dans tous les languages
- permet d'aller là où aucun autre langage ne peut vous amener
- Approfondissement sans fin:
- Théorie: théorie des catégories, théorie des types homotopiques, etc...
- Optim: compilateur
- Qualité: tests, preuves
- Organisation: capacité de contraindre de très haut vers très bas
*** Avantage compétitif
- France, Europe du sud & Functional Programming
- Maintenance >> production d'un nouveau produit
- Coût de la refactorisation
- "Make it work, Make it right, Make it fast" moins cher.
* Appendix
*** STM: Exemple (Concurrence) (1/2)
#+BEGIN_SRC java
class Account {
float balance;
synchronized void deposit(float amount){
balance += amount; }
synchronized void withdraw(float amount){
if (balance < amount) throw new OutOfMoneyError();
balance -= amount; }
synchronized void transfert(Account other, float amount){
other.withdraw(amount);
this.deposit(amount); }
}
#+END_SRC
Situation d'interblocage typique. (A transfert vers B et B vers A).
*** STM: Exemple (Concurrence) (2/2)
#+BEGIN_SRC haskell
deposit :: TVar Int -> Int -> STM ()
deposit acc n = do
bal <- readTVar acc
writeTVar acc (bal + n)
withdraw :: TVar Int -> Int -> STM ()
withdraw acc n = do
bal <- readTVar acc
if bal < n then retry
writeTVar acc (bal - n)
transfer :: TVar Int -> TVar Int -> Int -> STM ()
transfer from to n = do
withdraw from n
deposit to n
#+END_SRC
- pas de lock explicite, composition naturelle dans ~transfer~.
- si une des deux opération échoue toute la transaction échoue
- le système de type force cette opération a être atomique:
~atomically :: STM a -> IO a~

BIN
pres-Haskell-Intro.pdf Normal file

Binary file not shown.

View file

@ -0,0 +1,933 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Introduction à la Programmation Fonctionnelle en Haskell</title>
<meta name="description" content="Introduction à la Programmation Fonctionnelle en Haskell">
<meta name="author" content="Yann Esposito" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href=".reveal.js-3.2.0/css/reveal.css">
<link rel="stylesheet" href=".reveal.js-3.2.0/css/theme/default.css" id="theme">
<!-- For syntax highlighting -->
<link rel="stylesheet" href=".reveal.js-3.2.0/lib/css/zenburn.css">
<!-- If the query includes 'print-pdf', use the PDF print sheet -->
<script>
document.write( '<link rel="stylesheet" href=".reveal.js-3.2.0/css/print/' +
( window.location.search.match( /print-pdf/gi ) ? 'pdf' : 'paper' ) +
'.css" type="text/css" media="print">' );
</script>
<!--[if lt IE 9]>
<script src=".reveal.js-3.2.0/lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section>
<h1>Introduction à la Programmation Fonctionnelle en Haskell</h1>
<h3>Yann Esposito</h3>
<p>
<h4>&lt;2018-03-15 Thu&gt;</h4>
</p>
</section>
<section id="courte-introduction" class="level1">
<h1>Courte Introduction</h1>
<section id="prelude" class="level2">
<h2>Prelude</h2>
<p>Initialiser l'env de dev:</p>
<pre class="shell"><code>curl -sSL https://get.haskellstack.org/ | sh
stack new ipfh https://git.io/vbpej &amp;&amp; \
cd ipfh &amp;&amp; \
stack setup &amp;&amp; \
stack build &amp;&amp; \
stack test &amp;&amp; \
stack bench
</code></pre>
</section>
<section id="parcours-jusquà-haskell" class="level2">
<h2>Parcours jusqu'à Haskell</h2>
<section id="parcours-pro" class="level3">
<h3>Parcours Pro</h3>
<ul>
<li>Doctorat (machine learning, hidden markov models) 2004</li>
<li>Post doc (écriture d'un UI pour des biologistes en Java). 2006</li>
<li>Dev Airfrance, (Perl, scripts shell, awk, HTML, CSS, JS, XML...) 2006 → 2013</li>
<li>Dev (ruby, C, ML) pour GridPocket. (dev) 2009 → 2011, (impliqué) 2009 →</li>
<li>Clojure dev &amp; Machine Learning pour Vigiglobe. 2013 → 2016</li>
<li>Senior Clojure développeur chez Cisco. 2016 →</li>
</ul>
</section>
<section id="langages-de-programmations-basiques" class="level3">
<h3>Langages de programmations basiques</h3>
<ol>
<li>BASIC (MO5, Amstrad CPC 6129, Atari STf)</li>
<li>Logo (école primaire, + écriture d'un cours en 1ère année de Fac)</li>
<li>Pascal (lycée, fac)</li>
<li>C (fac)</li>
<li>ADA (fac)</li>
</ol>
</section>
<section id="langages-de-programmations-orientés-objet" class="level3">
<h3>Langages de programmations orientés objet</h3>
<ol>
<li>C++ (fac + outils de recherche pour doctorat)</li>
<li>Eiffel (fac)</li>
<li>Java (fac, UI en Java 1.6, Swing pour postdoc)</li>
<li>Objective-C (temps personnel, app iPhone, app Mac, Screensavers)</li>
</ol>
</section>
<section id="langages-moderne-de-script" class="level3">
<h3>Langages moderne de script</h3>
<ol>
<li>PHP (fac, site perso)</li>
<li>Python (fac, projets perso, jeux, etc...)</li>
<li>Awk (fac, Airfrance, ...)</li>
<li>Perl (Airfrance...)</li>
<li>Ruby (GridPocket, site perso v2)</li>
<li>Javascript:
<ul>
<li><em>Airfrance</em> basic prototype, jquery, etc..,</li>
<li>spine.js</li>
<li>backbone.js</li>
<li>Coffeescript</li>
<li>Cappuccino (Objective-J)</li>
<li>Sproutcore</li>
<li><em>Vigiglobe</em> actionhero (nodejs), angularjs v1</li>
</ul></li>
</ol>
</section>
<section id="langage-peu-reconnus" class="level3">
<h3>Langage peu (re)connus</h3>
<ol>
<li>Metapost</li>
<li>zsh (quasi lang de prog)</li>
<li>prolog</li>
</ol>
</section>
<section id="langages-fonctionnels" class="level3">
<h3>Langages fonctionnels</h3>
<ol>
<li>CamL</li>
<li>Haskell (Vigiglobe, personnal)</li>
<li>Clojure (Vigiglobe, Cisco)</li>
</ol>
</section>
</section>
<section id="quest-ce-que-la-programmation-fonctionnelle" class="level2">
<h2>Qu'est-ce que la programmation fonctionnelle?</h2>
<section id="von-neumann-architecture" class="level3">
<h3>Von Neumann Architecture</h3>
<pre><code> +--------------------------------+
| +----------------------------+ |
| | central processing unit | |
| | +------------------------+ | |
| | | Control Unit | | |
+------+ | | +------------------------+ | | +--------+
|input +---&gt; | +------------------------+ | +--&gt; output |
+------+ | | | Arithmetic/Logic Unit | | | +--------+
| | +------------------------+ | |
| +-------+---^----------------+ |
| | | |
| +-------v---+----------------+ |
| | Memory Unit | |
| +----------------------------+ |
+--------------------------------+
</code></pre>
<p>made with <a href="http://asciiflow.com" class="uri">http://asciiflow.com</a></p>
</section>
<section id="von-neumann-vs-church" class="level3">
<h3>Von Neumann vs Church</h3>
<ul>
<li>programmer à partir de la machine (Von Neumann)
<ul>
<li>tire vers l'optimisation</li>
<li>mots de bits, caches, détails de bas niveau</li>
<li>actions séquentielles</li>
<li><strong>1 siècle d'expérience</strong></li>
</ul></li>
</ul>
<div class="incremental">
<ul>
<li>programmer comme manipulation de symbole (Alonzo Church)
<ul>
<li>tire vers l'abstraction</li>
<li>plus proche des représentations mathématiques</li>
<li>ordre d'évaluation non imposé</li>
<li><strong>4000 ans d'expérience</strong></li>
</ul></li>
</ul>
</div>
</section>
<section id="histoire" class="level3">
<h3>Histoire</h3>
<ul>
<li>λ-Calculus, Alonzo Church &amp; Rosser 1936
<ul>
<li>Foundation, explicit side effect no implicit state</li>
</ul></li>
</ul>
<div class="incremental">
<ul>
<li>LISP (McCarthy 1960)
<ul>
<li>Garbage collection, higher order functions, dynamic typing</li>
</ul></li>
</ul>
</div>
<div class="incremental">
<ul>
<li>ML (1969-80)
<ul>
<li>Static typing, Algebraic Datatypes, Pattern matching</li>
</ul></li>
</ul>
</div>
<div class="incremental">
<ul>
<li>Miranda (1986) → Haskell (1992‥)
<ul>
<li>Lazy evaluation, pure</li>
</ul></li>
</ul>
</div>
</section>
<section id="retour-dexpérience-subjectif" class="level3">
<h3>Retour d'expérience subjectif</h3>
<p><em>pieds nus</em> (code machine, ASM)</p>
<div class="incremental">
<pre><code> _
/ \
/. ) _
___/ | / / \
.-&#39;__/ |( ( .\
\ | \___
)| \__`-.
</code></pre>
<p><em>Talons hauts</em> (C, Pascal, Java, C++, Perl, PHP, Python, Ruby, etc...)</p>
</div>
<div class="incremental">
<p><em>Tennis</em> (Clojure, Scheme, LISP, etc...)</p>
</div>
<div class="incremental">
<p><em>Voiture</em> (Haskell, Purescript, etc...)</p>
</div>
</section>
</section>
<section id="pourquoi-haskell" class="level2">
<h2>Pourquoi Haskell?</h2>
<section id="simplicité-par-labstraction" class="level3">
<h3>Simplicité par l'abstraction</h3>
<p><strong><code>/!\</code> SIMPLICITÉ ≠ FACILITÉ <code>/!\</code></strong></p>
<ul>
<li>mémoire (garbage collection)</li>
<li>ordre d'évaluation (non strict / lazy)</li>
<li>effets de bords (pur)</li>
<li>manipulation de code (referential transparency)</li>
</ul>
</section>
<section id="production-ready" class="level3">
<h3>Production Ready™</h3>
<ul>
<li>rapide
<ul>
<li>équivalent à Java (~ x2 du C)</li>
<li>parfois plus rapide que C</li>
<li>bien plus rapide que python et ruby</li>
</ul></li>
</ul>
<div class="incremental">
<ul>
<li>communauté solide
<ul>
<li>3k comptes sur Haskellers</li>
<li>&gt;30k sur reddit <em>(35k rust, 45k go, 50k nodejs, 4k ocaml, 13k clojure)</em></li>
<li>libs &gt;12k sur hackage</li>
</ul></li>
</ul>
</div>
<div class="incremental">
<ul>
<li>entreprises
<ul>
<li>Facebook (fighting spam, HAXL, ...)</li>
<li>beaucoup de startups, finance en général</li>
</ul></li>
</ul>
</div>
<div class="incremental">
<ul>
<li>milieu académique
<ul>
<li>fondations mathématiques</li>
<li>fortes influences des chercheurs</li>
<li>tire le langage vers le haut</li>
</ul></li>
</ul>
</div>
</section>
<section id="tooling" class="level3">
<h3>Tooling</h3>
<ul>
<li>compilateur (GHC)</li>
<li>gestion de projets ; cabal, stack, hpack, etc...</li>
<li>IDE / hlint ; rapidité des erreurs en cours de frappe</li>
<li>frameworks hors catégorie (servant, yesod)</li>
<li>ecosystèmes très matures et inovant
<ul>
<li>Elm (⇒ frontend)</li>
<li>Purescript (⇒ frontend)</li>
<li>GHCJS (⇒ frontend)</li>
<li>Idris (types dépendants)</li>
<li>Hackett (typed LISP avec macros)</li>
</ul></li>
</ul>
</section>
<section id="qualité" class="level3">
<h3>Qualité</h3>
<blockquote>
<p><em>Si ça compile alors il probable que ça marche</em></p>
</blockquote>
<div class="incremental">
<ul>
<li>test unitaires : chercher quelques erreurs manuellements</li>
</ul>
</div>
<div class="incremental">
<ul>
<li><em>test génératifs</em> : chercher des erreurs sur beaucoups de cas générés aléatoirement &amp; aide pour trouver l'erreur sur l'objet le plus simple</li>
</ul>
</div>
<div class="incremental">
<ul>
<li><em>finite state machine generative testing</em> : chercher des erreurs sur le déroulement des actions entre différents agents indépendants</li>
</ul>
</div>
<div class="incremental">
<ul>
<li><strong>preuves</strong>: chercher des erreur sur <strong>TOUTES</strong> les entrées possibles possible à l'aide du système de typage</li>
</ul>
</div>
</section>
</section>
</section>
<section id="premiers-pas-en-haskell" class="level1">
<h1>Premiers Pas en Haskell</h1>
<section id="hello-world-13" class="level3">
<h3>Hello World! (1/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> putStrLn <span class="st">&quot;Hello World!&quot;</span></code></pre></div>
<p><a href="~/.deft/pres-haskell/hello.hs">file:~/.deft/pres-haskell/hello.hs</a></p>
</section>
<section id="hello-world-23" class="level3">
<h3>Hello World! (2/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> putStrLn <span class="st">&quot;Hello World!&quot;</span></code></pre></div>
<ul>
<li><code>::</code> de type ;</li>
<li><code>=</code> égalité (la vrai, on peut interchanger ce qu'il y a des deux cotés) ;</li>
<li>le type de <code>putStrLn</code> est <code>String -&gt; IO ()</code> ;</li>
<li>le type de <code>main</code> est <code>IO ()</code>.</li>
</ul>
</section>
<section id="hello-world-33" class="level3">
<h3>Hello World! (3/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> putStrLn <span class="st">&quot;Hello World!&quot;</span></code></pre></div>
<ul>
<li>Le type <code>IO a</code> signifie: C'est une description d'une procédure qui quand elle est évaluée peut faire des actions d'IO et finalement retourne une valeur de type <code>a</code> ;</li>
<li><code>main</code> est le nom du point d'entrée du programme ;</li>
<li>Haskell runtime va chercher pour <code>main</code> et l'exécute.</li>
</ul>
</section>
<section id="what-is-your-name" class="level2">
<h2>What is your name?</h2>
<section id="what-is-your-name-13" class="level3">
<h3>What is your name? (1/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span>
putStrLn output</code></pre></div>
<p><a href="file:pres-haskell/name.hs" class="uri">file:pres-haskell/name.hs</a></p>
</section>
<section id="what-is-your-name-23" class="level3">
<h3>What is your name? (2/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span>
putStrLn output</code></pre></div>
<ul>
<li>l'indentation est importante !</li>
<li><code>do</code> commence une syntaxe spéciale qui permet de séquencer des actions <code>IO</code> ;</li>
<li>le type de <code>getLine</code> est <code>IO String</code> ;</li>
<li><code>IO String</code> signifie: Ceci est la description d'une procédure qui lorsqu'elle est évaluée peut faire des actions IO et à la fin retourne une valeur de type <code>String</code>.</li>
</ul>
</section>
<section id="what-is-your-name-33" class="level3">
<h3>What is your name? (3/3)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span>
putStrLn output</code></pre></div>
<ul>
<li>le type de <code>getLine</code> est <code>IO String</code></li>
<li>le type de <code>name</code> est <code>String</code></li>
<li><code>&lt;-</code> est une syntaxe spéciale qui n'apparait que dans la notation <code>do</code></li>
<li><code>&lt;-</code> signifie: évalue la procédure et attache la valeur renvoyée dans le nom à gauche de <code>&lt;-</code></li>
<li><code>let &lt;name&gt; = &lt;expr&gt;</code> signifie que <code>name</code> est interchangeable avec <code>expr</code> pour le reste du bloc <code>do</code>.</li>
<li>dans un bloc <code>do</code>, <code>let</code> n'a pas besoin d'être accompagné par <code>in</code> à la fin.</li>
</ul>
</section>
</section>
<section id="erreurs-classiques" class="level2">
<h2>Erreurs classiques</h2>
<section id="erreur-classique-1" class="level3">
<h3>Erreur classique #1</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> getLine <span class="fu">++</span> <span class="st">&quot;!&quot;</span>
putStrLn output</code></pre></div>
<pre><code>/Users/yaesposi/.deft/pres-haskell/name.hs:6:40: warning: [-Wdeferred-type-errors]
• Couldn&#39;t match expected type [Char]
with actual type IO String
• In the first argument of (++), namely getLine
In the second argument of (++), namely getLine ++ &quot;!&quot;
In the expression: &quot;Nice to meet you, &quot; ++ getLine ++ &quot;!&quot;
|
6 | let output = &quot;Nice to meet you, &quot; ++ getLine ++ &quot;!&quot;
| ^^^^^^^
Ok, one module loaded.
</code></pre>
</section>
<section id="erreur-classique-1-1" class="level3">
<h3>Erreur classique #1</h3>
<ul>
<li><code>String</code> est <code>[Char]</code></li>
<li>Haskell n'arrive pas à faire matcher le type <code>String</code> avec <code>IO String</code>.</li>
<li><code>IO a</code> et <code>a</code> sont différents</li>
</ul>
</section>
<section id="erreur-classique-2" class="level3">
<h3>Erreur classique #2</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
putStrLn <span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span></code></pre></div>
<pre><code>/Users/yaesposi/.deft/pres-haskell/name.hs:7:3: warning: [-Wdeferred-type-errors]
• Couldn&#39;t match expected type [Char] with actual type IO ()
• In the first argument of (++), namely
putStrLn &quot;Nice to meet you, &quot;
In a stmt of a &#39;do&#39; block:
putStrLn &quot;Nice to meet you, &quot; ++ name ++ &quot;!&quot;
In the expression:
do putStrLn &quot;Hello! What is your name?&quot;
name &lt;- getLine
putStrLn &quot;Nice to meet you, &quot; ++ name ++ &quot;!&quot;
|
7 | putStrLn &quot;Nice to meet you, &quot; ++ name ++ &quot;!&quot;
</code></pre>
</section>
<section id="erreur-classique-2-fix" class="level3">
<h3>Erreur classique #2 (fix)</h3>
<ul>
<li>Des parenthèses sont nécessaires</li>
<li>L'application de fonction se fait de gauche à droite</li>
</ul>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span>
<span class="ot">main ::</span> <span class="dt">IO</span> ()
main <span class="fu">=</span> <span class="kw">do</span>
putStrLn <span class="st">&quot;Hello! What is your name?&quot;</span>
name <span class="ot">&lt;-</span> getLine
putStrLn (<span class="st">&quot;Nice to meet you, &quot;</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">&quot;!&quot;</span>)</code></pre></div>
</section>
</section>
</section>
<section id="concepts-avec-exemples" class="level1">
<h1>Concepts avec exemples</h1>
<section id="concepts" class="level3">
<h3>Concepts</h3>
<ul>
<li><em>pureté</em> (par défaut)</li>
<li><em>evaluation paraisseuse</em> (par défaut)</li>
<li><em>ADT &amp; typage polymorphique</em></li>
</ul>
</section>
<section id="pureté-function-vs-proceduresubroutines" class="level3">
<h3><em>Pureté</em>: Function vs Procedure/Subroutines</h3>
<ul>
<li>Une <em>fonction</em> n'a pas d'effet de bord</li>
<li>Une <em>Procedure</em> ou <em>subroutine</em> but engendrer des effets de bords lors de son évaluation</li>
</ul>
</section>
<section id="pureté-function-vs-proceduresubroutines-exemple" class="level3">
<h3><em>Pureté</em>: Function vs Procedure/Subroutines (exemple)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">dist ::</span> <span class="dt">Double</span> <span class="ot">-&gt;</span> <span class="dt">Double</span> <span class="ot">-&gt;</span> <span class="dt">Double</span>
dist x y <span class="fu">=</span> sqrt (x<span class="fu">**</span><span class="dv">2</span> <span class="fu">+</span> y<span class="fu">**</span><span class="dv">2</span>)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">getName ::</span> <span class="dt">IO</span> <span class="dt">String</span>
getName <span class="fu">=</span> readLine</code></pre></div>
<ul>
<li><strong>IO a</strong><strong>IMPUR</strong> ; effets de bords hors evaluation :
<ul>
<li>lire un fichier ;</li>
<li>écrire sur le terminal ;</li>
<li>changer la valeur d'une variable en RAM est impur.</li>
</ul></li>
</ul>
</section>
<section id="pureté-gain-paralellisation-gratuite" class="level3">
<h3><em>Pureté</em>: Gain, paralellisation gratuite</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">import </span><span class="dt">Foreign.Lib</span> (f)
<span class="co">-- f :: Int -&gt; Int</span>
<span class="co">-- f = ???</span>
foo <span class="fu">=</span> sum results
<span class="kw">where</span> results <span class="fu">=</span> map f [<span class="dv">1</span><span class="fu">..</span><span class="dv">100</span>]</code></pre></div>
<div class="incremental">
<p><strong><code>fmap</code> FTW!!!!! Assurance d'avoir le même résultat avec 32 cœurs</strong></p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">import </span><span class="dt">Foreign.Lib</span> (f)
<span class="co">-- f :: Int -&gt; Int</span>
<span class="co">-- f = ???</span>
foo <span class="fu">=</span> sum results
<span class="kw">where</span> results <span class="fu">=</span> fmap f [<span class="dv">1</span><span class="fu">..</span><span class="dv">100</span>]</code></pre></div>
</div>
</section>
<section id="pureté-structures-de-données-immuable" class="level3">
<h3><em>Pureté</em>: Structures de données immuable</h3>
<p>Purely functional data structures, <em>Chris Okasaki</em></p>
<p>Thèse en 1996, et un livre.</p>
<p>Opérations sur les listes, tableaux, arbres de complexité amortie equivalent ou proche (pire des cas facteur log(n)) de celle des structures de données muables.</p>
</section>
<section id="évaluation-parraisseuse-stratégies-dévaluations" class="level3">
<h3><em>Évaluation parraisseuse</em>: Stratégies d'évaluations</h3>
<p><code>(h (f a) (g b))</code> peut s'évaluer:</p>
<ul>
<li><code>a</code><code>(f a)</code><code>b</code><code>(g b)</code><code>(h (f a) (g b))</code></li>
<li><code>b</code><code>a</code><code>(g b)</code><code>(f a)</code><code>(h (f a) (g b))</code></li>
<li><code>a</code> et <code>b</code> en parallèle puis <code>(f a)</code> et <code>(g b)</code> en parallèle et finallement <code>(h (f a) (g b))</code></li>
<li><code>h</code><code>(f a)</code> seulement si nécessaire et puis <code>(g b)</code> seulement si nécessaire</li>
</ul>
<p>Par exemple: <code>(def h (λx.λy.(+ x x)))</code> il n'est pas nécessaire d'évaluer <code>y</code>, dans notre cas <code>(g b)</code></p>
</section>
<section id="évaluation-parraisseuse-exemple-1" class="level3">
<h3><em>Évaluation parraisseuse</em>: Exemple 1</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">quickSort [] <span class="fu">=</span> []
quickSort (x<span class="fu">:</span>xs) <span class="fu">=</span> quickSort (filter (<span class="fu">&lt;</span>x) xs)
<span class="fu">++</span> [x]
<span class="fu">++</span> quickSort (filter (<span class="fu">&gt;=</span>x) xs)
minimum list <span class="fu">=</span> head (quickSort list)</code></pre></div>
<p>Un appel à <code>minimum longList</code> ne vas pas ordonner toute la liste. Le travail s'arrêtera dès que le premier élément de la liste ordonnée sera trouvé.</p>
<p><code>take k (quickSort list)</code> est en <code>O(n + k log k)</code><code>n = length list</code>. Alors qu'avec une évaluation stricte: <code>O(n log n)</code>.</p>
</section>
<section id="évaluation-parraisseuse-structures-de-données-infinies-zip" class="level3">
<h3><em>Évaluation parraisseuse</em>: Structures de données infinies (zip)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">zip<span class="ot"> ::</span> [a] <span class="ot">-&gt;</span> [b] <span class="ot">-&gt;</span> [(a,b)]
zip [] _ <span class="fu">=</span> []
zip _ [] <span class="fu">=</span> []
zip (x<span class="fu">:</span>xs) (y<span class="fu">:</span>ys) <span class="fu">=</span> (x,y)<span class="fu">:</span>zip xs ys</code></pre></div>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">zip [<span class="dv">1</span><span class="fu">..</span>] [<span class="ch">&#39;a&#39;</span>,<span class="ch">&#39;b&#39;</span>,<span class="ch">&#39;c&#39;</span>]</code></pre></div>
<p>s'arrête et renvoie :</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">[(<span class="dv">1</span>,<span class="ch">&#39;a&#39;</span>), (<span class="dv">2</span>,<span class="ch">&#39;b&#39;</span>), (<span class="dv">3</span>, <span class="ch">&#39;c&#39;</span>)]</code></pre></div>
</section>
<section id="adt-typage-polymorphique" class="level3">
<h3><em>ADT &amp; Typage polymorphique</em></h3>
<p>Algebraic Data Types.</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Void</span> <span class="fu">=</span> <span class="dt">Void</span> <span class="dt">Void</span> <span class="co">-- 0 valeur possible!</span>
<span class="kw">data</span> <span class="dt">Unit</span> <span class="fu">=</span> () <span class="co">-- 1 seule valeur possible</span>
<span class="kw">data</span> <span class="dt">Product</span> x y <span class="fu">=</span> <span class="dt">P</span> x y
<span class="kw">data</span> <span class="dt">Sum</span> x y <span class="fu">=</span> <span class="dt">S1</span> x <span class="fu">|</span> <span class="dt">S2</span> y</code></pre></div>
<p>Soit <code>#x</code> le nombre de valeurs possibles pour le type <code>x</code> alors:</p>
<ul>
<li><code>#(Product x y) = #x * #y</code></li>
<li><code>#(Sum x y) = #x + #y</code></li>
</ul>
</section>
<section id="adt-typage-polymorphique-inférence-de-type" class="level3">
<h3><em>ADT &amp; Typage polymorphique</em>: Inférence de type</h3>
<p>À partir de :</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">zip [] _ <span class="fu">=</span> []
zip _ [] <span class="fu">=</span> []
zip (x<span class="fu">:</span>xs) (y<span class="fu">:</span>ys) <span class="fu">=</span> (x,y)<span class="fu">:</span>zip xs ys</code></pre></div>
<p>le compilateur peut déduire:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">zip<span class="ot"> ::</span> [a] <span class="ot">-&gt;</span> [b] <span class="ot">-&gt;</span> [(a,b)]</code></pre></div>
</section>
<section id="composabilité" class="level2">
<h2>Composabilité</h2>
<section id="composabilité-vs-modularité" class="level3">
<h3>Composabilité vs Modularité</h3>
<p>Modularité: soit un <code>a</code> et un <code>b</code>, je peux faire un <code>c</code>. ex: x un graphique, y une barre de menu =&gt; une page <code>let page = mkPage ( graphique, menu )</code></p>
<p>Composabilité: soit deux <code>a</code> je peux faire un autre <code>a</code>. ex: x un widget, y un widget =&gt; un widget <code>let page = x &lt;+&gt; y</code></p>
<p>Gain d'abstraction, moindre coût.</p>
<p><strong>Hypothèses fortes sur les <code>a</code></strong></p>
</section>
<section id="exemples" class="level3">
<h3>Exemples</h3>
<ul>
<li><strong>Semi-groupes</strong> 〈+〉</li>
<li><p><strong>Monoides</strong> 〈0,+〉</p></li>
<li><strong>Catégories</strong> 〈obj(C),hom(C),∘〉</li>
<li>Foncteurs <code>fmap</code> (<code>(&lt;$&gt;)</code>)</li>
<li>Foncteurs Applicatifs <code>ap</code> (<code>(&lt;*&gt;)</code>)</li>
<li>Monades <code>join</code></li>
<li>Traversables <code>map</code></li>
<li><p>Foldables <code>reduce</code></p></li>
</ul>
</section>
</section>
</section>
<section id="catégories-de-bugs-évités-avec-haskell" class="level1">
<h1>Catégories de bugs évités avec Haskell</h1>
<section id="real-productions-bugs" class="level3">
<h3>Real Productions Bugs™</h3>
<p>Bug vu des dizaines de fois en prod malgré:</p>
<ol>
<li>specifications fonctionnelles</li>
<li>spécifications techniques</li>
<li>tests unitaires</li>
<li>3 envs, dev, recette/staging/pre-prod, prod</li>
<li>Équipe de QA qui teste en recette</li>
</ol>
<p>Solutions simples.</p>
</section>
<section id="null-pointer-exception-erreur-classique-1" class="level3">
<h3>Null Pointer Exception: Erreur classique (1)</h3>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">int <span class="at">foo</span>( x ) <span class="op">{</span>
<span class="cf">return</span> x <span class="op">+</span> <span class="dv">1</span><span class="op">;</span>
<span class="op">}</span></code></pre></div>
</section>
<section id="null-pointer-exception-erreur-classique-2" class="level3">
<h3>Null Pointer Exception: Erreur classique (2)</h3>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">int <span class="at">foo</span>( x ) <span class="op">{</span>
...
<span class="kw">var</span> y <span class="op">=</span> <span class="at">do_shit_1</span>(x)<span class="op">;</span>
...
<span class="cf">return</span> <span class="at">do_shit_20</span>(x)
<span class="op">}</span>
...
<span class="kw">var</span> val <span class="op">=</span> <span class="at">foo</span>(<span class="dv">26</span>/<span class="dv">2334</span> <span class="op">-</span> <span class="va">Math</span>.<span class="at">sqrt</span>(<span class="dv">2</span>))<span class="op">;</span></code></pre></div>
<div class="incremental">
<pre><code>888888b. .d88888b. 888 888 888b d888 888 888 888 888 888
888 &quot;88b d88P&quot; &quot;Y88b 888 888 8888b d8888 888 888 888 888 888
888 .88P 888 888 888 888 88888b.d88888 888 888 888 888 888
8888888K. 888 888 888 888 888Y88888P888 888 888 888 888 888
888 &quot;Y88b 888 888 888 888 888 Y888P 888 888 888 888 888 888
888 888 888 888 888 888 888 Y8P 888 Y8P Y8P Y8P Y8P Y8P
888 d88P Y88b. .d88P Y88b. .d88P 888 &quot; 888 &quot; &quot; &quot; &quot; &quot;
8888888P&quot; &quot;Y88888P&quot; &quot;Y88888P&quot; 888 888 888 888 888 888 888
</code></pre>
<p><strong>Null Pointer Exception</strong></p>
</div>
</section>
<section id="null-pointer-exception-data-type-maybe" class="level3">
<h3>Null Pointer Exception: Data type <code>Maybe</code></h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Maybe</span> a <span class="fu">=</span> <span class="dt">Just</span> a <span class="fu">|</span> <span class="dt">Nothing</span>
<span class="fu">...</span>
<span class="ot">foo ::</span> <span class="dt">Maybe</span> a
<span class="fu">...</span>
myFunc x <span class="fu">=</span> <span class="kw">let</span> t <span class="fu">=</span> foo x <span class="kw">in</span>
<span class="kw">case</span> t <span class="kw">of</span>
<span class="dt">Just</span> someValue <span class="ot">-&gt;</span> doThingsWith someValue
<span class="dt">Nothing</span> <span class="ot">-&gt;</span> doThingWhenNothingIsReturned</code></pre></div>
<p>Le compilateur oblige à tenir compte des cas particuliers! Impossible d'oublier.</p>
</section>
<section id="null-pointer-excepton-etat" class="level3">
<h3>Null Pointer Excepton: Etat</h3>
<ul>
<li>Rendre impossibe de fabriquer un état qui devrait être impossible d'avoir.</li>
<li>Pour aller plus loin voir, FRP, CQRS/ES, Elm-architecture, etc...</li>
</ul>
</section>
<section id="erreur-due-à-une-typo" class="level3">
<h3>Erreur due à une typo</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Foo</span> x <span class="fu">=</span> <span class="dt">LongNameWithPossibleError</span> x
<span class="fu">...</span>
foo (<span class="dt">LongNameWithPosibleError</span> x) <span class="fu">=</span> <span class="fu">...</span></code></pre></div>
<p><strong>Erreur à la compilation</strong>: Le nom d'un champ n'est pas une string (voir les objets JSON).</p>
</section>
<section id="echange-de-parameters" class="level3">
<h3>Echange de parameters</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Personne</span> <span class="fu">=</span> <span class="dt">Personne</span> {<span class="ot"> uid ::</span> <span class="dt">Int</span>,<span class="ot"> age ::</span> <span class="dt">Int</span> }
<span class="ot">foo ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Personne</span> <span class="co">-- ??? uid ou age?</span></code></pre></div>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">newtype</span> <span class="dt">UID</span> <span class="fu">=</span> <span class="dt">UID</span> <span class="dt">Int</span> <span class="kw">deriving</span> (<span class="dt">Eq</span>)
<span class="kw">data</span> <span class="dt">Personne</span> <span class="fu">=</span> <span class="dt">Personne</span> {<span class="ot"> uid ::</span> <span class="dt">UID</span>,<span class="ot"> age ::</span> <span class="dt">Int</span> }
<span class="ot">foo ::</span> <span class="dt">UDI</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Personne</span> <span class="co">-- Impossible de confondre</span></code></pre></div>
</section>
<section id="changement-intempestif-dun-etat-global" class="level3">
<h3>Changement intempestif d'un Etat Global</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">foo ::</span> <span class="dt">GlobalState</span> <span class="ot">-&gt;</span> x</code></pre></div>
<p><strong><code>foo</code> ne peut pas changer <code>GlobalState</code></strong></p>
</section>
</section>
<section id="organisation-du-code" class="level1">
<h1>Organisation du Code</h1>
<section id="grands-concepts" class="level3">
<h3>Grands Concepts</h3>
<p>Procedure vs Functions:</p>
<table>
<tbody>
<tr class="odd">
<td>Gestion d'une configuration globale</td>
</tr>
<tr class="even">
<td>Gestion d'un état global</td>
</tr>
<tr class="odd">
<td>Gestion des Erreurs</td>
</tr>
<tr class="even">
<td>Gestion des IO</td>
</tr>
</tbody>
</table>
</section>
<section id="monades" class="level3">
<h3>Monades</h3>
<p>Pour chacun de ces <em>problèmes</em> il existe une monade:</p>
<table>
<tbody>
<tr class="odd">
<td>Gestion d'une configuration globale</td>
<td><code>Reader</code></td>
</tr>
<tr class="even">
<td>Gestion d'un état global</td>
<td><code>State</code></td>
</tr>
<tr class="odd">
<td>Gestion des Erreurs</td>
<td><code>Either</code></td>
</tr>
<tr class="even">
<td>Gestion des IO</td>
<td><code>IO</code></td>
</tr>
</tbody>
</table>
</section>
<section id="effets" class="level3">
<h3>Effets</h3>
<p>Gestion de plusieurs Effets dans la même fonction:</p>
<ul>
<li>MTL</li>
<li>Free Monad</li>
<li>Freer Monad</li>
</ul>
<p>Idée: donner à certaines sous-fonction accès à une partie des effets seulement.</p>
<p>Par exemple:</p>
<ul>
<li>limiter une fonction à la lecture de la DB mais pas l'écriture.</li>
<li>limiter l'écriture à une seule table</li>
<li>interdire l'écriture de logs</li>
<li>interdire l'écriture sur le disque dur</li>
<li>etc...</li>
</ul>
</section>
<section id="exemple-dans-un-code-réel-1" class="level3">
<h3>Exemple dans un code réel (1)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="co">-- | ConsumerBot type, the main monad in which the bot code is written with.</span>
<span class="co">-- Provide config, state, logs and IO</span>
<span class="kw">type</span> <span class="dt">ConsumerBot</span> m a <span class="fu">=</span>
( <span class="dt">MonadState</span> <span class="dt">ConsumerState</span> m
, <span class="dt">MonadReader</span> <span class="dt">ConsumerConf</span> m
, <span class="dt">MonadLog</span> (<span class="dt">WithSeverity</span> <span class="dt">Doc</span>) m
, <span class="dt">MonadBaseControl</span> <span class="dt">IO</span> m
, <span class="dt">MonadSleep</span> m
, <span class="dt">MonadPubSub</span> m
, <span class="dt">MonadIO</span> m
) <span class="ot">=&gt;</span> m a</code></pre></div>
</section>
<section id="exemple-dans-un-code-réel-2" class="level3">
<h3>Exemple dans un code réel (2)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">bot ::</span> <span class="dt">Manager</span>
<span class="ot">-&gt;</span> <span class="dt">RotatingLog</span>
<span class="ot">-&gt;</span> <span class="dt">Chan</span> <span class="dt">RedditComment</span>
<span class="ot">-&gt;</span> <span class="dt">TVar</span> <span class="dt">RedbotConfs</span>
<span class="ot">-&gt;</span> <span class="dt">Severity</span>
<span class="ot">-&gt;</span> <span class="dt">IO</span> ()
bot manager rotLog pubsub redbots minSeverity <span class="fu">=</span> <span class="kw">do</span>
TC.setDefaultPersist TC.filePersist
<span class="kw">let</span> conf <span class="fu">=</span> <span class="dt">ConsumerConf</span>
{ rhconf <span class="fu">=</span> <span class="dt">RedditHttpConf</span> { _connMgr <span class="fu">=</span> manager }
, commentStream <span class="fu">=</span> pubsub
}
void <span class="fu">$</span> autobot
<span class="fu">&amp;</span> flip runReaderT conf
<span class="fu">&amp;</span> flip runStateT (initState redbots)
<span class="fu">&amp;</span> flip runLoggingT (renderLog minSeverity rotLog)</code></pre></div>
</section>
<section id="règles-pragmatiques" class="level2">
<h2>Règles <strong>pragmatiques</strong></h2>
<section id="organisation-en-fonction-de-la-complexité" class="level3">
<h3>Organisation en fonction de la complexité</h3>
<blockquote>
<p>Make it work, make it right, make it fast</p>
</blockquote>
<ul>
<li>Simple: directement IO (YOLO!)</li>
<li>Medium: Haskell Design Patterns: The Handle Pattern: <a href="https://jaspervdj.be/posts/2018-03-08-handle-pattern.html" class="uri">https://jaspervdj.be/posts/2018-03-08-handle-pattern.html</a></li>
<li>Medium (bis): MTL / Free / Freeer / Effects...</li>
<li>Gros: Three Layer Haskell Cake: <a href="http://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html" class="uri">http://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html</a>
<ul>
<li>Layer 1: Imperatif</li>
<li>Orienté Objet (Level 2 / 2')</li>
<li>Fonctionnel</li>
</ul></li>
</ul>
</section>
<section id="couches" class="level3">
<h3>3 couches</h3>
<ul>
<li><strong>Imperatif</strong>: ReaderT IO
<ul>
<li>Insérer l'état dans une <code>TVar</code>, <code>MVar</code> ou <code>IORef</code> (concurrence)</li>
</ul></li>
<li><strong>Orienté Objet</strong>:
<ul>
<li>Handle / MTL / Free...</li>
<li>donner des access <code>UserDB</code>, <code>AccessTime</code>, <code>APIHTTP</code>...</li>
</ul></li>
<li><strong>Fonctionnel</strong>: Business Logic <code>f : Handlers -&gt; Inputs -&gt; Command</code></li>
</ul>
</section>
<section id="services-lib" class="level3">
<h3>Services / Lib</h3>
<p>Service: <code>init</code> / <code>start</code> / <code>close</code> + methodes... Lib: methodes sans état interne.</p>
</section>
</section>
</section>
<section id="conclusion" class="level1">
<h1>Conclusion</h1>
<section id="pourquoi-haskell-1" class="level3">
<h3>Pourquoi Haskell?</h3>
<ul>
<li>avantage compétitif: qualité x productivité hors norme</li>
<li>changera son approche de la programmation</li>
<li>les concepts appris sont utilisables dans tous les languages</li>
<li>permet d'aller là où aucun autre langage ne peut vous amener</li>
<li>Approfondissement sans fin:
<ul>
<li>Théorie: théorie des catégories, théorie des types homotopiques, etc...</li>
<li>Optim: compilateur</li>
<li>Qualité: tests, preuves</li>
<li>Organisation: capacité de contraindre de très haut vers très bas</li>
</ul></li>
</ul>
</section>
<section id="avantage-compétitif" class="level3">
<h3>Avantage compétitif</h3>
<ul>
<li>France, Europe du sud &amp; Functional Programming</li>
<li>Maintenance &gt;&gt; production d'un nouveau produit</li>
<li>Coût de la refactorisation</li>
<li>&quot;Make it work, Make it right, Make it fast&quot; moins cher.</li>
</ul>
</section>
</section>
<section id="appendix" class="level1">
<h1>Appendix</h1>
<section id="stm-exemple-concurrence-12" class="level3">
<h3>STM: Exemple (Concurrence) (1/2)</h3>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java"><span class="kw">class</span> Account {
<span class="dt">float</span> balance;
<span class="kw">synchronized</span> <span class="dt">void</span> <span class="fu">deposit</span>(<span class="dt">float</span> amount){
balance += amount; }
<span class="kw">synchronized</span> <span class="dt">void</span> <span class="fu">withdraw</span>(<span class="dt">float</span> amount){
<span class="kw">if</span> (balance &lt; amount) <span class="kw">throw</span> <span class="kw">new</span> <span class="fu">OutOfMoneyError</span>();
balance -= amount; }
<span class="kw">synchronized</span> <span class="dt">void</span> <span class="fu">transfert</span>(Account other, <span class="dt">float</span> amount){
other.<span class="fu">withdraw</span>(amount);
<span class="kw">this</span>.<span class="fu">deposit</span>(amount); }
}</code></pre></div>
<p>Situation d'interblocage typique. (A transfert vers B et B vers A).</p>
</section>
<section id="stm-exemple-concurrence-22" class="level3">
<h3>STM: Exemple (Concurrence) (2/2)</h3>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">deposit ::</span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> ()
deposit acc n <span class="fu">=</span> <span class="kw">do</span>
bal <span class="ot">&lt;-</span> readTVar acc
writeTVar acc (bal <span class="fu">+</span> n)
<span class="ot">withdraw ::</span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> ()
withdraw acc n <span class="fu">=</span> <span class="kw">do</span>
bal <span class="ot">&lt;-</span> readTVar acc
<span class="kw">if</span> bal <span class="fu">&lt;</span> n <span class="kw">then</span> retry
writeTVar acc (bal <span class="fu">-</span> n)
<span class="ot">transfer ::</span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> ()
transfer from to n <span class="fu">=</span> <span class="kw">do</span>
withdraw from n
deposit to n</code></pre></div>
<ul>
<li>pas de lock explicite, composition naturelle dans <code>transfer</code>.</li>
<li>si une des deux opération échoue toute la transaction échoue</li>
<li>le système de type force cette opération a être atomique: <code>atomically :: STM a -&gt; IO a</code></li>
</ul>
</section>
</section>
</div>
<script src=".reveal.js-3.2.0/lib/js/head.min.js"></script>
<script src=".reveal.js-3.2.0/js/reveal.js"></script>
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: false,
// available themes are in /css/theme
theme: Reveal.getQueryHash().theme || 'default',
// default/cube/page/concave/zoom/linear/fade/none
transition: Reveal.getQueryHash().transition || 'linear',
// Optional libraries used to extend on reveal.js
dependencies: [
{ src: '/.reveal.js-3.2.0/lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: '/.reveal.js-3.2.0/plugin/markdown/showdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '/.reveal.js-3.2.0/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '/.reveal.js-3.2.0/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: '/.reveal.js-3.2.0/plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: '/.reveal.js-3.2.0/plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
]
});
</script>
</body>
</html>

Binary file not shown.

View file

@ -16,8 +16,8 @@
<body>
<header>
<h1 class="title">Resume</h1>
<h2 class="author">Yann Esposito</h2>
<h3 class="date">26 July 2016</h3>
<p class="author">Yann Esposito</p>
<p class="date">26 July 2016</p>
</header>
<nav id="TOC">
<ul>
@ -53,9 +53,9 @@
</nav>
<h1 id="yann-esposito">Yann Esposito</h1>
<p></p>
<p><a href="./resume.pdf">PDF Version</a></p>
<p></p>
<table>
<tbody>
<tr class="odd">

Binary file not shown.

View file

@ -41,9 +41,9 @@
<section id="yann-esposito" class="level1">
<h1>Yann Esposito</h1>
<p></p>
<p><a href="./resume.pdf">PDF Version</a></p>
<p></p>
<table>
<tbody>
<tr class="odd">