934 lines
45 KiB
HTML
934 lines
45 KiB
HTML
|
<!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>
|