ability to build org mode + pres Haskell
This commit is contained in:
parent
16e32f1f7f
commit
fa66e280b4
18 changed files with 2660 additions and 11 deletions
Binary file not shown.
BIN
README.pdf
BIN
README.pdf
Binary file not shown.
|
@ -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.
|
@ -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>
|
||||
|
|
BIN
druid/druid.pdf
BIN
druid/druid.pdf
Binary file not shown.
BIN
index.beamer.pdf
BIN
index.beamer.pdf
Binary file not shown.
|
@ -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
BIN
index.pdf
Binary file not shown.
BIN
pres-Haskell-Intro.beamer.pdf
Normal file
BIN
pres-Haskell-Intro.beamer.pdf
Normal file
Binary file not shown.
869
pres-Haskell-Intro.html
Normal file
869
pres-Haskell-Intro.html
Normal 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"><2018-03-15 Thu></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">Qu’est-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 d’expérience subjectif</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#pourquoi-haskell">Pourquoi Haskell?</a><ul>
|
||||
<li><a href="#simplicité-par-labstraction">Simplicité par l’abstraction</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 & Typage polymorphique</em></a></li>
|
||||
<li><a href="#adt-typage-polymorphique-inférence-de-type"><em>ADT & 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 d’un 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 l’env de dev:</p>
|
||||
<pre class="shell"><code>curl -sSL https://get.haskellstack.org/ | sh
|
||||
stack new ipfh https://git.io/vbpej && \
|
||||
cd ipfh && \
|
||||
stack setup && \
|
||||
stack build && \
|
||||
stack test && \
|
||||
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 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 & 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 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>
|
||||
<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">Qu’est-ce que la programmation fonctionnelle?</h2>
|
||||
<h3 id="von-neumann-architecture">Von Neumann Architecture</h3>
|
||||
<pre><code> +--------------------------------+
|
||||
| +----------------------------+ |
|
||||
| | central processing unit | |
|
||||
| | +------------------------+ | |
|
||||
| | | Control Unit | | |
|
||||
+------+ | | +------------------------+ | | +--------+
|
||||
|input +---> | +------------------------+ | +--> 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 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>
|
||||
<h3 id="histoire">Histoire</h3>
|
||||
<ul>
|
||||
<li>λ-Calculus, Alonzo Church & 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 d’expérience subjectif</h3>
|
||||
<p><em>pieds nus</em> (code machine, ASM)</p>
|
||||
<div class="incremental">
|
||||
<pre><code> _
|
||||
/ \
|
||||
/. ) _
|
||||
___/ | / / \
|
||||
.-'__/ |( ( .\
|
||||
\ | \___
|
||||
)| \__`-.
|
||||
</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 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>
|
||||
<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>>30k sur reddit <em>(35k rust, 45k go, 50k nodejs, 4k ocaml, 13k clojure)</em></li>
|
||||
<li>libs >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 & 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>
|
||||
<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">"Hello World!"</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">"Hello World!"</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 -> 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">"Hello World!"</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>
|
||||
<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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</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>
|
||||
<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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</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><-</code> est une syntaxe spéciale qui n’apparait que dans la notation <code>do</code></li>
|
||||
<li><code><-</code> signifie: évalue la procédure et attache la valeur renvoyée dans le nom à gauche de <code><-</code></li>
|
||||
<li><code>let <name> = <expr></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>
|
||||
<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">"Hello! What is your name?"</span>
|
||||
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> getLine <span class="fu">++</span> <span class="st">"!"</span>
|
||||
putStrLn output</code></pre></div>
|
||||
<pre><code>/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.
|
||||
</code></pre>
|
||||
<h3 id="erreur-classique-1-1">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>
|
||||
<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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
putStrLn <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</span></code></pre></div>
|
||||
<pre><code>/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 ++ "!"
|
||||
</code></pre>
|
||||
<h3 id="erreur-classique-2-fix">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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
putStrLn (<span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</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 & 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> 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>
|
||||
<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">-></span> <span class="dt">Double</span> <span class="ot">-></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>
|
||||
<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 -> 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 -> 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 n’est 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"><</span>x) xs)
|
||||
<span class="fu">++</span> [x]
|
||||
<span class="fu">++</span> quickSort (filter (<span class="fu">>=</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> où <code>n = length list</code>. Alors qu’avec 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">-></span> [b] <span class="ot">-></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">'a'</span>,<span class="ch">'b'</span>,<span class="ch">'c'</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">'a'</span>), (<span class="dv">2</span>,<span class="ch">'b'</span>), (<span class="dv">3</span>, <span class="ch">'c'</span>)]</code></pre></div>
|
||||
<h3 id="adt-typage-polymorphique"><em>ADT & 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 & 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">-></span> [b] <span class="ot">-></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 => 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 => un widget <code>let page = x <+> y</code></p>
|
||||
<p>Gain d’abstraction, 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>(<$>)</code>)</li>
|
||||
<li>Foncteurs Applicatifs <code>ap</code> (<code>(<*>)</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 "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
|
||||
</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">-></span> doThingsWith someValue
|
||||
<span class="dt">Nothing</span> <span class="ot">-></span> doThingWhenNothingIsReturned</code></pre></div>
|
||||
<p>Le compilateur oblige à tenir compte des cas particuliers! Impossible d’oublier.</p>
|
||||
<h3 id="null-pointer-excepton-etat">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>
|
||||
<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 d’un champ n’est 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">-></span> <span class="dt">Int</span> <span class="ot">-></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">-></span> <span class="dt">Int</span> <span class="ot">-></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 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">-></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 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>
|
||||
<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 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>
|
||||
<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">=></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">-></span> <span class="dt">RotatingLog</span>
|
||||
<span class="ot">-></span> <span class="dt">Chan</span> <span class="dt">RedditComment</span>
|
||||
<span class="ot">-></span> <span class="dt">TVar</span> <span class="dt">RedbotConfs</span>
|
||||
<span class="ot">-></span> <span class="dt">Severity</span>
|
||||
<span class="ot">-></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">&</span> flip runReaderT conf
|
||||
<span class="fu">&</span> flip runStateT (initState redbots)
|
||||
<span class="fu">&</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 -> Inputs -> 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 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>
|
||||
<h3 id="avantage-compétitif">Avantage compétitif</h3>
|
||||
<ul>
|
||||
<li>France, Europe du sud & Functional Programming</li>
|
||||
<li>Maintenance >> production d’un 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 < 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>
|
||||
<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">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">STM</span> ()
|
||||
deposit acc n <span class="fu">=</span> <span class="kw">do</span>
|
||||
bal <span class="ot"><-</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">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">STM</span> ()
|
||||
withdraw acc n <span class="fu">=</span> <span class="kw">do</span>
|
||||
bal <span class="ot"><-</span> readTVar acc
|
||||
<span class="kw">if</span> bal <span class="fu"><</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">-></span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></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 -> 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
847
pres-Haskell-Intro.org
Normal 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)~ où ~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
BIN
pres-Haskell-Intro.pdf
Normal file
Binary file not shown.
933
pres-Haskell-Intro.reveal.html
Normal file
933
pres-Haskell-Intro.reveal.html
Normal 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><2018-03-15 Thu></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 && \
|
||||
cd ipfh && \
|
||||
stack setup && \
|
||||
stack build && \
|
||||
stack test && \
|
||||
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 & 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 +---> | +------------------------+ | +--> 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 & 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> _
|
||||
/ \
|
||||
/. ) _
|
||||
___/ | / / \
|
||||
.-'__/ |( ( .\
|
||||
\ | \___
|
||||
)| \__`-.
|
||||
</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>>30k sur reddit <em>(35k rust, 45k go, 50k nodejs, 4k ocaml, 13k clojure)</em></li>
|
||||
<li>libs >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 & 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">"Hello World!"</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">"Hello World!"</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 -> 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">"Hello World!"</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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</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><-</code> est une syntaxe spéciale qui n'apparait que dans la notation <code>do</code></li>
|
||||
<li><code><-</code> signifie: évalue la procédure et attache la valeur renvoyée dans le nom à gauche de <code><-</code></li>
|
||||
<li><code>let <name> = <expr></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">"Hello! What is your name?"</span>
|
||||
<span class="kw">let</span> output <span class="fu">=</span> <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> getLine <span class="fu">++</span> <span class="st">"!"</span>
|
||||
putStrLn output</code></pre></div>
|
||||
<pre><code>/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.
|
||||
</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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
putStrLn <span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</span></code></pre></div>
|
||||
<pre><code>/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 ++ "!"
|
||||
</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">"Hello! What is your name?"</span>
|
||||
name <span class="ot"><-</span> getLine
|
||||
putStrLn (<span class="st">"Nice to meet you, "</span> <span class="fu">++</span> name <span class="fu">++</span> <span class="st">"!"</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 & 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">-></span> <span class="dt">Double</span> <span class="ot">-></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 -> 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 -> 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"><</span>x) xs)
|
||||
<span class="fu">++</span> [x]
|
||||
<span class="fu">++</span> quickSort (filter (<span class="fu">>=</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> où <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">-></span> [b] <span class="ot">-></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">'a'</span>,<span class="ch">'b'</span>,<span class="ch">'c'</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">'a'</span>), (<span class="dv">2</span>,<span class="ch">'b'</span>), (<span class="dv">3</span>, <span class="ch">'c'</span>)]</code></pre></div>
|
||||
</section>
|
||||
<section id="adt-typage-polymorphique" class="level3">
|
||||
<h3><em>ADT & 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 & 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">-></span> [b] <span class="ot">-></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 => 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 => un widget <code>let page = x <+> 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>(<$>)</code>)</li>
|
||||
<li>Foncteurs Applicatifs <code>ap</code> (<code>(<*>)</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 "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
|
||||
</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">-></span> doThingsWith someValue
|
||||
<span class="dt">Nothing</span> <span class="ot">-></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">-></span> <span class="dt">Int</span> <span class="ot">-></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">-></span> <span class="dt">Int</span> <span class="ot">-></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">-></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">=></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">-></span> <span class="dt">RotatingLog</span>
|
||||
<span class="ot">-></span> <span class="dt">Chan</span> <span class="dt">RedditComment</span>
|
||||
<span class="ot">-></span> <span class="dt">TVar</span> <span class="dt">RedbotConfs</span>
|
||||
<span class="ot">-></span> <span class="dt">Severity</span>
|
||||
<span class="ot">-></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">&</span> flip runReaderT conf
|
||||
<span class="fu">&</span> flip runStateT (initState redbots)
|
||||
<span class="fu">&</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 -> Inputs -> 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 & Functional Programming</li>
|
||||
<li>Maintenance >> production d'un nouveau produit</li>
|
||||
<li>Coût de la refactorisation</li>
|
||||
<li>"Make it work, Make it right, Make it fast" 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 < 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">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">STM</span> ()
|
||||
deposit acc n <span class="fu">=</span> <span class="kw">do</span>
|
||||
bal <span class="ot"><-</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">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">STM</span> ()
|
||||
withdraw acc n <span class="fu">=</span> <span class="kw">do</span>
|
||||
bal <span class="ot"><-</span> readTVar acc
|
||||
<span class="kw">if</span> bal <span class="fu"><</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">-></span> <span class="dt">TVar</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></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 -> 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.
|
@ -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.
|
@ -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">
|
||||
|
|
Loading…
Reference in a new issue