tag:linuxfr.org,2005:/tags/ocaml/publicLinuxFr.org : les contenus étiquetés avec « ocaml »2024-03-17T11:37:16+01:00/favicon.pngtag:linuxfr.org,2005:Diary/410962024-03-13T22:51:17+01:002024-03-13T22:51:17+01:00autocsv2sql : un utilitaire pour convertir ses CSV sans se poser de question, "écris" en OCamlLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<p>Cher Journal,</p>
<p>J'ai probablement mal cherché dans les tréfonds de l'internet, mais je rêvais depuis longtemps d'un bête utilitaire en CLI pour me convertir un CSV en SQL sans me poser de question, ie. je lui donne le fichier et il se débrouille avec les types de données, l'ordre de création de table.</p>
<p>C'est maintenant chose faite avec <a href="https://github.com/ontologiae/autocsv2sql">autocsv2sql</a>, un utilitaire que j'ai "écris" en OCaml, et qui fait globalement bien le taf pour la 20aine de CSV que j'ai testé.</p>
<p>Alors quand je dis "écris", vous aurez compris qu'un LLM m'a beaucoup aidé à l'écrire, eh oui, je suis maintenant trop une fainéasse pour me lancer là dedans sans, et j'avoue que c'est le meilleur outil anti-procrastination que je connaisse.</p>
<p>Alors pour l'anecdote, il n'a évidemment pas été fichu d'écrire du code qui fonctionne, j'ai du lui décrire intégralement la fonction analyze_data_lines - et encore, j'ai du passer derrière - pour avoir une définition correcte. Deux tiers du temps a été consacré à corriger des bugs, bidouiller pour solutionner des problèmes comme le nombre de ligne et surtout gérer le <code>;</code> à la place du , à la fin d'une clause INSERT.<br>
Les Inserts sont générés par blocs de 1000 lignes pour éviter des temps de chargement interminables</p>
<p>Les vrais camélistes seront sans doute horrifiés devant la qualité du code : il est très impératif. En utilisant la librairie batteries, on pourrait sans doute écrire tout cela de façon bien plus élégante. Le LLM a tendance a peu utiliser les pattern match.</p>
<p>Vous me direz sans doute que cela existe en Python ou autre langage non compilé, mais l'intérêt avec OCaml, c'est qu'on compile, et ça ne se met pas à tomber en panne 6 mois plus tard parce que la lib pymachin est passée de la 3.1.6 à la 3.1.7</p>
<p>Voilà, en espérant que ça aide.</p>
<div><a href="https://linuxfr.org/users/montaigne/journaux/autocsv2sql-un-utilitaire-pour-convertir-ses-csv-sans-se-poser-de-question-ecris-en-ocaml.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/135111/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/montaigne/journaux/autocsv2sql-un-utilitaire-pour-convertir-ses-csv-sans-se-poser-de-question-ecris-en-ocaml#comments">ouvrir dans le navigateur</a>
</p>
Ontologiahttps://linuxfr.org/nodes/135111/comments.atomtag:linuxfr.org,2005:Bookmark/66852023-06-21T15:22:03+02:002023-06-21T15:22:03+02:00ACM Programming Languages Software Award goes to OCaml researchers <a href="https://www.cst.cam.ac.uk/news/acm-programming-languages-software-award-goes-ocaml-researchers">https://www.cst.cam.ac.uk/news/acm-programming-languages-software-award-goes-ocaml-researchers</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/131638/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/colargol/liens/acm-programming-languages-software-award-goes-to-ocaml-researchers#comments">ouvrir dans le navigateur</a>
</p>
Colargolhttps://linuxfr.org/nodes/131638/comments.atomtag:linuxfr.org,2005:Bookmark/65992023-06-05T05:52:52+02:002023-06-05T05:52:52+02:00[podcast] For those who just don’t Git it (interview with Pierre-Étienne Meunier)<a href="https://stackoverflow.blog/2023/05/23/for-those-who-just-dont-git-it-ep-573/">https://stackoverflow.blog/2023/05/23/for-those-who-just-dont-git-it-ep-573/</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/131467/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/gilcot/liens/podcast-for-those-who-just-don-t-git-it-interview-with-pierre-etienne-meunier#comments">ouvrir dans le navigateur</a>
</p>
Gil Cot ✔https://linuxfr.org/nodes/131467/comments.atomtag:linuxfr.org,2005:News/402712022-02-01T19:40:19+01:002022-02-01T19:40:19+01:00De OCaml à ReScript : création d'un nouveau langage ?Licence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Depuis toujours, le compilateur propose deux manières pour générer un programme exécutable à partir d’un code source OCaml : produire un programme binaire (dépendant de l’architecture donc) ou un byte code qui peut être réutilisé sur n’importe quelle plateforme.</p>
<p>Il y a dix ans, le projet <a href="https://ocsigen.org/js_of_ocaml/">js_of_ocaml</a> apparaissait, permettant de transformer ce bytecode (que pratiquement personne n’utilise) en code JavaScript. Ce projet a ouvert une porte dans l’univers web, puisqu’il permet d’utiliser la force du langage OCaml (typage, réutilisation des bibliothèques existantes) directement dans le navigateur. Il devient possible de contrôler un formulaire saisi par l’utilisateur dans le navigateur, ou sur le serveur avec le même code : il suffit d’inclure la même bibliothèque dans la chaîne de compilation JavaScript et dans la chaîne de compilation du serveur.</p>
</div><ul><li>lien nᵒ 1 : <a title="https://ocsigen.org/js_of_ocaml/latest/manual/overview" hreflang="en" href="https://linuxfr.org/redirect/109820">Js_of_ocaml , manuel</a></li><li>lien nᵒ 2 : <a title="https://reasonml.github.io/en/try" hreflang="en" href="https://linuxfr.org/redirect/109821">Test en ligne</a></li><li>lien nᵒ 3 : <a title="https://www.techatbloomberg.com/blog/bucklescript-1-0-release-arrived/" hreflang="en" href="https://linuxfr.org/redirect/109822">Annonce de la naissance de Bucklescript</a></li><li>lien nᵒ 4 : <a title="https://rescript-lang.org/" hreflang="en" href="https://linuxfr.org/redirect/109823">Rescript</a></li></ul><div><p>Le problème du projet js_of_ocaml vient du fait qu’il se nourrit du bytecode généré par ocaml : le code JavaScript qu’il produit est un code binaire qui n’est pas destiné à être lu ou modifié. Il faut faire confiance à la chaîne de compilation qui garantit que le code qui s’exécute est bien celui correspondant au code source. De plus, étant donné que l’on passe par du bytecode, le code suit la représentation mémoire utilisée par OCaml. Une liste chaînée par exemple, est représentée en JavaScript avec la même structure qu’elle le serait en C, alors que des types natifs JavaScript auraient pu être utilisés.</p>
<h3 id="toc-bucklescript">Bucklescript</h3>
<p>C’est dans ce contexte qu’apparaît en 2016 <a href="https://www.techatbloomberg.com/blog/bucklescript-1-0-release-arrived/">Bucklescript (EN)</a>. Ce projet, propose d’utiliser le compilateur OCaml pour générer du code JavaScript natif. Il ne s’agit plus cette fois de transformer du bytecode en code JavaScript, mais de prendre le code source, pour l’adapter directement, avec toutes les optimisations possibles.</p>
<p>Le code suivant (exemple tiré depuis l'<a href="https://reasonml.github.io/en/try">outil de test en ligne (EN)</a> :</p>
<pre><code class="Ocaml"><span class="k">let</span> <span class="k">rec</span> <span class="n">hanoi</span> <span class="n">n</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">=</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">></span> <span class="mi">0</span>
<span class="k">then</span>
<span class="o">(</span><span class="n">hanoi</span> <span class="o">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="o">)</span> <span class="n">a</span> <span class="n">c</span> <span class="n">b</span><span class="o">;</span>
<span class="nn">Js</span><span class="p">.</span><span class="n">log</span> <span class="o">{</span><span class="n">j</span><span class="o">|</span><span class="nc">Move</span> <span class="n">disk</span> <span class="n">from</span> <span class="n">pole</span> <span class="o">$</span><span class="n">a</span> <span class="k">to</span> <span class="n">pole</span> <span class="o">$</span><span class="n">b</span><span class="o">|</span><span class="n">j</span><span class="o">};</span>
<span class="n">hanoi</span> <span class="o">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="o">)</span> <span class="n">c</span> <span class="n">b</span> <span class="n">a</span><span class="o">)</span>
<span class="k">let</span> <span class="o">_</span> <span class="o">=</span> <span class="n">hanoi</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span></code></pre>
<p>est dès lors transformé en ce code JavaScript :</p>
<pre><code class="js"><span class="c1">// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE</span>
<span class="s1">'use strict'</span><span class="p">;</span>
<span class="kd">function</span> <span class="nx">hanoi</span><span class="p">(</span><span class="nx">_n</span><span class="p">,</span> <span class="nx">_a</span><span class="p">,</span> <span class="nx">b</span><span class="p">,</span> <span class="nx">_c</span><span class="p">)</span> <span class="p">{</span>
<span class="k">while</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">c</span> <span class="o">=</span> <span class="nx">_c</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="nx">_a</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">n</span> <span class="o">=</span> <span class="nx">_n</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">n</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">;</span>
<span class="p">}</span>
<span class="nx">hanoi</span><span class="p">(</span><span class="nx">n</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">c</span><span class="p">,</span> <span class="nx">b</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">"Move disk from pole "</span> <span class="o">+</span> <span class="nx">a</span> <span class="o">+</span> <span class="s2">" to pole "</span> <span class="o">+</span> <span class="nx">b</span><span class="p">);</span>
<span class="nx">_c</span> <span class="o">=</span> <span class="nx">a</span><span class="p">;</span>
<span class="nx">_a</span> <span class="o">=</span> <span class="nx">c</span><span class="p">;</span>
<span class="nx">_n</span> <span class="o">=</span> <span class="nx">n</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">continue</span> <span class="p">;</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="nx">hanoi</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
<span class="nx">exports</span><span class="p">.</span><span class="nx">hanoi</span> <span class="o">=</span> <span class="nx">hanoi</span><span class="p">;</span>
<span class="cm">/* Not a pure module */</span></code></pre>
<p>Le projet, soutenu par Facebook, s’accompagne également d’une nouvelle syntaxe, <a href="https://reasonml.github.io/">Reason (EN)</a>, qui a pour but de faciliter l’accès au langage et d’éviter la difficulté d’accès liée à OCaml. Ce langage/projet prend pied dans le monde JavaScript, est compatible avec <a href="https://fr.wikipedia.org/wiki/npm" title="Définition Wikipédia">npm</a> pour gérer les paquets, et grâce à la force du langage OCaml, permet d’unifier deux univers différents. On assiste à des projets tels que <a href="https://www.outrunlabs.com/revery/">revery (EN)</a>, qui permet d’écrire des applications lourdes (avec SDL) ou web à partir d’un code unique, et comme le langage n’est qu’une couche syntaxique au langage OCaml, apporte également de la visibilité au langage.</p>
<p>Sauf que cette compilation au plus près des sources a un prix : celle de hacker le compilateur OCaml, et d’être dépendant d’une version donnée. Les versions d’OCaml évoluent, mais le code de bucklescript reste figé sur une version datant de 2017 (4.06), sans bénéficier des dernières avancées. De plus, la syntaxe Reason est mise en avant, OCaml étant présenté comme syntaxe alternative. Au final, il y a assez peu de porosité entre ces deux univers : le gestionnaire de paquet opam reste le gestionnaire officiel pour OCaml, <a href="https://esy.sh/">esy (EN)</a> et npm sont utilisables avec Reason, et bien que quelques passerelles existent, les deux univers coexistent l’un à côté de l’autre sans réellement fusionner.</p>
<h3 id="toc-rescript">ReScript</h3>
<p>En 2020, Bucklescript et Reason deviennent <a href="https://rescript-lang.org/">ReScript</a>. Derrière ce changement de nom se cache également un changement de direction : OCaml n’est plus présenté comme syntaxe alternative — même s’il est toujours utilisé dans la chaîne de compilation, le monde JavaScript seul est pleinement assumé. On peut supposer que nous sommes en train d’assister à la naissance d’un nouveau langage qui prend son envol à partir d’OCaml (comme F# l’a fait également en son temps, passant d’un simple backend .NET pour OCaml à un langage indépendant et intéressant). Même si l’on peut regretter une dispersion dans les ressources, souhaitons bonne chance à ReScript !</p>
<p><abbr title="Note des modérateurs">N. D. M. :</abbr> le compilateur est sous <a href="https://github.com/rescript-lang/rescript-compiler/blob/master/LICENSE">LGPLv3 avec exception pour les liens</a> et la documentation du langage sous <a href="https://github.com/rescript-lang/syntax/blob/master/LICENSE">MIT</a>.</p>
</div><div><a href="https://linuxfr.org/news/de-ocaml-a-rescript-creation-d-un-nouveau-langage.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/122996/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/de-ocaml-a-rescript-creation-d-un-nouveau-langage#comments">ouvrir dans le navigateur</a>
</p>
chimrodYsabeau 🧶 🧦palm123SnarkBenoît SibaudtisaacObi MOvmagninNicolas CasanovagascheLtrlghttps://linuxfr.org/nodes/122996/comments.atomtag:linuxfr.org,2005:Bookmark/41112022-01-12T10:28:46+01:002022-01-12T10:28:46+01:00Multicore OCaml: December 2021 and the Big PR<a href="https://alan.petitepomme.net/cwn/2022.01.11.html#4">https://alan.petitepomme.net/cwn/2022.01.11.html#4</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/126547/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/benoit_in/liens/multicore-ocaml-december-2021-and-the-big-pr#comments">ouvrir dans le navigateur</a>
</p>
Benoît Laurenthttps://linuxfr.org/nodes/126547/comments.atomtag:linuxfr.org,2005:News/408272022-01-10T06:59:12+01:002022-01-10T06:59:12+01:00🏆 Meilleures contributions LinuxFr.org : les primées de décembre 2021<div><p>Nous continuons sur notre lancée de récompenser celles et ceux qui chaque mois contribuent au site <em>LinuxFr.org</em> (dépêches, commentaires, logo, journaux, correctifs, etc.). Vous n’êtes pas sans risquer de gagner un livre des éditions <a href="https://www.editions-eyrolles.com/">Eyrolles</a> ou <a href="https://www.editions-eni.fr/">ENI</a>. Voici les gagnants du mois de décembre 2021 :</p>
<ul>
<li>
<em><a href="//linuxfr.org/users/papey">Papey</a></em>, pour sa dépêche « <a href="//linuxfr.org/news/l-ong-noyb-porte-plainte-pour-corruption-contre-la-cnil-irlandaise">L'ONG Noyb porte plainte pour corruption contre la CNIL irlandaise</a> » ;</li>
<li>
<em><a href="//linuxfr.org/users/magsoft">magsoft</a></em>, pour sa dépêche « <a href="//linuxfr.org/news/compter-automatiquement-les-mots-prononces-sur-les-chaines-d-information-continue">Compter automatiquement les mots prononcés sur les chaînes d'information continue</a> » ;</li>
<li>
<em><a href="//linuxfr.org/users/dinosaure">Dinosaure</a></em>, pour sa dépêche « <a href="//linuxfr.org/news/mirageos-un-micro-os-unikernel-en-ocaml">MirageOS - un micro OS (unikernel) en OCaml</a> » ;</li>
<li>
<em><a href="//linuxfr.org/users/xcomcmdr">xcomcmdr</a></em>, pour sa dépêche « <a href="//linuxfr.org/news/net-6-est-sorti-la-version-la-plus-rapide-a-ce-jour">.NET 6 est sorti - La version la plus rapide à ce jour</a> » ;</li>
<li>
<em><a href="//linuxfr.org/users/gnoucat">GnouCat</a></em>, pour sa dépêche « <a href="//linuxfr.org/news/greycess-knight-rpg-sortie-de-la-premiere-version">Greycess Knight RPG : sortie de la première version !</a> » ;</li>
<li>
<em><a href="//linuxfr.org/users/johnny_jazeix">Johnny_Jazeix</a></em>, pour sa dépêche « <a href="//linuxfr.org/news/gcompris-sort-en-version-2-0-pour-les-fetes-de-fin-d-annee">GCompris sort en version 2.0 pour les fêtes de fin d'année</a> » ;</li>
</ul>
<p>Les livres gagnés sont détaillés en seconde partie de la dépêche. N’oubliez pas de contribuer, <em>LinuxFr.org</em> vit pour vous et par vous !</p>
</div><ul><li>lien nᵒ 1 : <a title="https://linuxfr.org/proposer-un-contenu" hreflang="fr" href="https://linuxfr.org/redirect/109731">Contribuez</a></li><li>lien nᵒ 2 : <a title="https://linuxfr.org/wiki/participer-a-linuxfr" hreflang="fr" href="https://linuxfr.org/redirect/109732">Tous les moyens (ou presque) de participer</a></li><li>lien nᵒ 3 : <a title="https://linuxfr.org/news/meilleures-contributions-linuxfr-org-les-primees-de-novembre-2021" hreflang="fr" href="https://linuxfr.org/redirect/109733">Récompenses précédentes (novembre 2021)</a></li></ul><div><h3 id="toc-les-livres--sélectionnés">Les livres 📚 sélectionnés</h3>
<ul>
<li>
<em><a href="https://www.editions-eyrolles.com/Livre/9782212679076/data-science-par-la-pratique">Data Science par la pratique — Fondamentaux avec Python — Préparez-vous aux métiers du futur ! — 2<sup>e</sup> édition</a></em> ;</li>
<li>
<em><a href="https://www.editions-eyrolles.com/Livre/9782416004568/l-intelligence-artificielle-en-pratique-avec-python">L'intelligence artificielle en pratique avec Python — Recherche, optimisation, apprentissage</a></em> ;</li>
<li>
<em><a href="https://www.editions-eni.fr/livre/debuter-avec-azure-concepts-fondamentaux-et-mise-en-oeuvre-9782409033230">Débuter avec Azure — Concepts fondamentaux et mise en œuvre</a></em> ;</li>
<li>
<em><a href="https://www.editions-eni.fr/livre/scripting-python-sous-linux-developpez-vos-outils-systeme-9782409025679">Scripting Python sous Linux — Développez vos outils système</a></em> ;</li>
<li>
<em><a href="https://www.editions-eyrolles.com/Livre/9782212137934/debuter-avec-linux">Débuter avec LINUX — Maîtrisez votre système aux petits oignons</a></em>.</li>
</ul>
<p><img src="https://linuxfr.org/images/logos/logo_eclair.png" alt="Bandeau LinuxFr.org"></p>
<p>Certaines personnes n’ont pas pu être jointes ou n’ont pas répondu. Les lots ont été réattribués automatiquement. N’oubliez pas de mettre une adresse de courriel valable dans votre compte ou lors de la proposition d’une dépêche. En effet, c’est notre seul moyen de vous contacter, que ce soit pour les lots ou des questions sur votre dépêche lors de sa modération. Tous nos remerciements aux contributeurs du site ainsi qu’aux éditions <a href="https://www.editions-eyrolles.com/">Eyrolles</a> et <a href="https://www.editions-eni.fr/">ENI</a>.</p>
<table>
<thead>
<tr>
<th><a href="https://www.editions-eni.fr"><img src="//img.linuxfr.org/img/68747470733a2f2f692e696d6775722e636f6d2f52464679635a642e706e67/RFFycZd.png" alt="Logo éditions ENI" title="Source : https://i.imgur.com/RFFycZd.png"></a></th>
<th> </th>
<th><a href="https://www.editions-eyrolles.com"><img src="//img.linuxfr.org/img/68747470733a2f2f692e696d6775722e636f6d2f4f3064593778552e706e67/O0dY7xU.png" alt="Logo éditions Eyrolles" title="Source : https://i.imgur.com/O0dY7xU.png"></a></th>
</tr>
</thead>
<tbody>
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
</div><div><a href="https://linuxfr.org/news/meilleures-contributions-linuxfr-org-les-primees-de-decembre-2021.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/126442/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/meilleures-contributions-linuxfr-org-les-primees-de-decembre-2021#comments">ouvrir dans le navigateur</a>
</p>
Florent Zarahttps://linuxfr.org/nodes/126442/comments.atomtag:linuxfr.org,2005:News/402582021-09-25T12:07:02+02:002021-09-28T07:58:34+02:00OCaml en 2021Licence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>La version 4.13.0 du langage OCaml est sortie le 24 septembre 2021, sept mois après OCaml 4.12.0 sortie le 24 février 2021.</p>
<p>OCaml est un langage fonctionnel de la <a href="https://fr.wikipedia.org/wiki/ML_(langage)">famille des langages ML</a> (dont font partie SML et F#). Il s’agit d’un langage fonctionnel multi‐paradigme fortement typé qui permet de mélanger librement les trois paradigmes : fonctionnel, impératif et objet. La plus grande spécificité d’OCaml dans le paysage des langages fonctionnels (Haskell, Rust, F#…) est probablement son système de module : les modules d’OCaml font partie intégrante du langage, et il est par exemple possible de décrire des modules paramétrés par d’autres modules (à travers des <a href="https://ocaml.org/manual/moduleexamples.html#s%3Afunctors">foncteurs</a>).</p>
<p>La grande nouveauté de cette année 2021 est la convergence de l’environnement d’exécution entre la version standard d’OCaml et le prototype d’OCaml multi-cœur. Cette convergence amorce une nouvelle étape dans la transition vers OCaml multi-cœur. Au-delà des progrès vers OCaml multi-cœur, cette année 2021 a vu une de nombreuses avancées pour le langage OCaml et son compilateur que ce soit en termes d’architectures supportées, de messages d’erreurs, de fonctionnalités du système de types, mais aussi des améliorations de confort pour les programmeurs que ce soit au niveau des outils de profilage, de la gestion des avertissements ou de la bibliothèque standard.</p>
</div><ul><li>lien nᵒ 1 : <a title="https://ocaml.org" hreflang="en" href="https://linuxfr.org/redirect/108415">Site officiel</a></li><li>lien nᵒ 2 : <a title="https://ocaml.org/manual" hreflang="en" href="https://linuxfr.org/redirect/108416">Manuel de référence d'OCaml</a></li><li>lien nᵒ 3 : <a title="https://ocamlverse.github.io/" hreflang="en" href="https://linuxfr.org/redirect/109164">ocamlverse</a></li><li>lien nᵒ 4 : <a title="https://discuss.ocaml.org/" hreflang="en" href="https://linuxfr.org/redirect/109165">Forum officiel</a></li><li>lien nᵒ 5 : <a title="https://github.com/ocaml/ocaml/blob/4.13/Changes" hreflang="en" href="https://linuxfr.org/redirect/109166">Changelog</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="#toc-la-route-vers-le-multi-c%C5%93ur-et-ocaml-50">La route vers le multi-cœur et OCaml 5.0</a></li>
<li><a href="#toc-une-prise-en-charge-%C3%A9tendue-de-risc-v-%C3%A0-macosarm64">Une prise en charge étendue de RISC-V à macOS/ARM64</a></li>
<li>
<a href="#toc-de-meilleurs-messages-derreurs">De meilleurs messages d’erreurs</a><ul>
<li><a href="#toc-des-messages-derreurs-plus-d%C3%A9taill%C3%A9s-pour-les-foncteurs">Des messages d’erreurs plus détaillés pour les foncteurs</a></li>
<li><a href="#toc-confusion-entre-module-et-module-types">Confusion entre module et module types</a></li>
<li><a href="#toc-une-explication-des-probl%C3%A8mes-de-r%C3%A9gularit%C3%A9">Une explication des problèmes de régularité</a></li>
</ul>
</li>
<li>
<a href="#toc-am%C3%A9liorations-de-lexp%C3%A9rience-utilisateur">Améliorations de l’expérience utilisateur</a><ul>
<li><a href="#toc-statmemprof-profiler-la-m%C3%A9moire-sur-des-programmes-en-production">Statmemprof : profiler la mémoire sur des programmes en production.</a></li>
<li><a href="#toc-des-noms-pour-les-warnings">Des noms pour les warnings</a></li>
<li><a href="#toc-et-la-stdlib-sagrandit">Et la Stdlib s’agrandit</a></li>
<li><a href="#toc-des-piles-dappels-plus-expressives">Des piles d’appels plus expressives</a></li>
</ul>
</li>
<li>
<a href="#toc-plus-de-types-pour-les-utilisateurs-experts">Plus de types pour les utilisateurs experts</a><ul>
<li><a href="#toc-des-noms-pour-les-types-existentiels">Des noms pour les types existentiels</a></li>
<li><a href="#toc-de-linjectivit%C3%A9-pour-vos-types">De l’injectivité pour vos types</a></li>
</ul>
</li>
<li><a href="#toc-au-del%C3%A0-docaml-multi-c%C5%93ur">Au-delà d’OCaml multi-cœur</a></li>
</ul>
<h2 id="toc-la-route-vers-le-multi-cœur-et-ocaml-50">La route vers le multi-cœur et OCaml 5.0</h2>
<p>Une des limites de l’implémentation actuelle de l’environnement d’exécution d’OCaml est son utilisation d’un verrou global. Ce verrou empêche les applications <em>multithreads</em> de bénéficier du parallélisme des fils d’exécution (<em>threads</em>). Au cours du temps, il y a eu plusieurs tentatives d’enlever ce verrou. La dernière initiative a germé chez OCaml Labs vers 2014-2015. Pour éviter les échecs précédents, cette initiative a décidé de se concentrer sur deux points : une compatibilité descendante presque parfaite avec la version monocœur d’OCaml, et une intégration incrémentale dans la branche principale d’OCaml. Ce travail de fond a commencé à être visible dans OCaml 4.10.0. Mais il s’est notablement accéléré dans OCaml 4.12.0. Une grande partie du travail dans OCaml 4.12 et 4.13 a été consacrée à diminuer les divergences entre l’environnement d’OCaml multi-cœur et la version principale d’OCaml.</p>
<p>Par exemple, un des changements majeurs prévus pour OCaml multi-cœur est la gestion des pointeurs pointant en dehors de la mémoire gérée par OCaml, sans être gardés par des métadonnées (parce que, par exemple, ils ont été alloués par une bibliothèque C externe). Dans la version monocœur d’OCaml, ces pointeurs étaient gérés en gardant une trace des zones mémoires allouées par OCaml. En passant à un environnement d’exécution multi-cœur, cette stratégie devient prohibitive en coût de synchronisation. Ces pointeurs nus ne seront donc pas autorisés dans OCaml multi-cœur. Pour assurer une évolution en douceur, OCaml 4.12.0 a ajouté deux options de configuration : une option pour désactiver la gestion des pointeurs nus directement pour les audacieux ; et une version plus prudente qui rajoute un test dynamique de la présence de ces pointeurs nus. Cette dernière option est notamment utilisée pour tester toutes les bibliothèques et programmes disponibles sur Opam (le dépôt de paquets d’OCaml).</p>
<p>Un autre point important est la gestion de l’ordonnancement entre l’utilisateur et l’environnement d’exécution (<em>runtime</em>). Dans la version monocœur d’OCaml, l’environnement d’exécution reprend la main à chaque allocation. Cela lui donne l’occasion de vérifier si le Glaneur de Cellules (GC) à du travail à faire, ou s’il faut s’occuper de signaux en attente. Une conséquence est qu’il est possible d’écrire du code numérique qui n’alloue jamais et ne rend jamais la main à l’environnement d’exécution. En absence de parallélisme, ce comportement est plus une curiosité qu’autre chose. Mais pour multi-cœur OCaml, ce comportement égoïste n’est plus de mise. Dans sa conception actuelle, OCaml multi-cœur a une phase de GC en parallèle, pendant laquelle tous les fils d’exécution exécutent une passe de GC de manière synchrone. Il n’est donc pas question qu’un fil d’exécution bloque le GC de tous les autres fils. Le compilateur natif a donc été modifié dans OCaml 4.13.0 pour s’assurer qu’un fil d’exécution passe toujours la main à l’environnement d’exécution dans un temps borné.</p>
<p>Un élément qui commence à apparaître dans les discussions sur OCaml multi-cœur est que l’on se rapproche d’un point où il ne reste plus qu’à faire le grand saut et intégrer le <em>runtime</em> multi-cœur, et absorber les petites pertes de performances inévitables pour le code séquentiel.</p>
<p>La première version d’OCaml qui intégrera la prise en charge du multi-cœur sera OCaml 5.0. Cette nouvelle majeure commencera avec une période de transition durant laquelle la branche 4 sera maintenue activement.</p>
<p>Cette première version d’OCaml multi-cœur n’intègrera pas la partie la plus innovante de la proposition initiale, le système d’effet, et se contentera d’exposer une bibliothèque de domaines et quelques API de plus haut niveau, bâtis au-dessus de cette bibliothèque de domaine.</p>
<p>Le but est de découpler la partie <em>runtime</em> du développement d’OCaml multi-cœur du travail de conception sur le système d’effet qui requiert encore des efforts de conception. </p>
<h2 id="toc-une-prise-en-charge-étendue-de-risc-v-à-macosarm64">Une prise en charge étendue de RISC-V à macOS/ARM64</h2>
<p>Le compilateur OCaml gère deux modes de compilation : un mode <em>bytecode</em> qui fonctionne sur toute architecture où un compilateur C est disponible ; et un mode natif qui émet directement des binaires natifs. Ce mode natif est d’ailleurs le seul utilisateur du système objet d’OCaml au sein du compilateur lui-même.</p>
<p>Cette gestion native requiert de s’adapter aux nouvelles familles de processeurs et aux variations d’ABI suivant les systèmes d’exploitation. OCaml 4.11.0 a ainsi vu apparaître la prise en charge du RISC-V sous Linux. De manière similaire, la prise en charge pré-existante pour ARM64 a été étendue pour couvrir les conventions d’appels de macOS dans OCaml 4.12.0 .</p>
<h2 id="toc-de-meilleurs-messages-derreurs">De meilleurs messages d’erreurs</h2>
<p>Écrire des messages d’erreurs utiles est une tâche plus difficile qu’il n’y paraît. Il peut être tentant de communiquer une erreur interne sur l’implémentation ou d’évoquer une théorie avec laquelle l’utilisateur n’est pas familier. Un autre problème assez fréquent pour les erreurs de types dans OCaml est que le vérificateur de type est optimisé pour vérifier rapidement que le code est bien typé. Avec ce mode de fonctionnement, on ne découvre parfois une erreur uniquement après qu’une série de petites erreurs nous ait mené à une situation impossible.</p>
<p>En bref, il reste pas mal de travail à faire pour améliorer les messages d’erreurs d’OCaml. Mais cette année 2021 a vu quelques progrès intéressants, et d’autres sont déjà intégrés ou en cours d’intégration dans la version de développement d’OCaml.</p>
<h3 id="toc-des-messages-derreurs-plus-détaillés-pour-les-foncteurs">Des messages d’erreurs plus détaillés pour les foncteurs</h3>
<p>Les foncteurs sont des fonctionnalités uniques d’OCaml. Ils permettent de décrire des modules qui dépendent d’autres modules. Par exemple, la définition d’un module <code>Graphe</code> peut prendre comme argument un module <code>Sommet</code> et un module <code>Arete</code> : </p>
<pre><code class="ocaml"><span class="k">module</span> <span class="nc">Graphe</span><span class="o">(</span><span class="nc">Sommet</span><span class="o">:</span><span class="nc">SOMMET</span><span class="o">)(</span><span class="nc">Arete</span><span class="o">:</span><span class="nc">ARETE</span><span class="o">)</span> <span class="o">=</span> <span class="k">struct</span> <span class="o">...</span> <span class="k">end</span></code></pre>
<p>Je peux ensuite instancier ce foncteur avec diverses implémentations de <code>ARETE</code> et <code>SOMMET</code>.</p>
<p>Par exemple :</p>
<pre><code class="ocaml"><span class="k">module</span> <span class="nc">Graphe_basique</span> <span class="o">=</span> <span class="nc">Graphe</span><span class="o">(</span><span class="nc">Sommet_basique</span><span class="o">)(</span><span class="nc">Arete_basique</span><span class="o">)</span>
<span class="k">module</span> <span class="nc">Graphe_colore</span> <span class="o">=</span> <span class="nc">Graphe</span><span class="o">(</span><span class="nc">Sommet_colore</span><span class="o">)(</span><span class="nc">Arete_basique</span><span class="o">)</span></code></pre>
<p>Cette formulation en termes de foncteur permet de décrire des algorithmes de graphes indépendamment de l’implémentation des arêtes ou sommets (sont-ils nommés ? colorés ?).</p>
<p>Avant OCaml 4.13, les erreurs liées à ces foncteurs pouvaient être très verbeuses. Par exemple, si j’applique le foncteur <code>Graphe</code> avec un argument en trop :</p>
<pre><code class="ocaml"><span class="k">module</span> <span class="nc">G</span> <span class="o">=</span> <span class="nc">Graphe</span><span class="o">(</span><span class="nc">Etiquette</span><span class="o">)(</span><span class="nc">Sommet</span><span class="o">)(</span><span class="nc">Arete</span><span class="o">)</span></code></pre>
<p>Le vérificateur de type d’OCaml se plaignait que le module Etiquette n’est pas un <code>SOMMET</code>, ce qui donne un message d’erreur qui ressemble à cela :</p>
<pre><code> Modules do not match:
sig type t = string end
is not included in
SOMMET
The value `label' is required but not provided
The value `create' is required but not provided
The type `label' is required but not provided
The value `equal' is required but not provided
The value `hash' is required but not provided
The value `compare' is required but not provided
</code></pre>
<p>Avec OCaml 4.13.0, le vérificateur de type prend de la hauteur et essaye d’identifier des erreurs de haut niveau dans les erreurs liées aux foncteurs : est-ce que l’utilisateur n’aurait pas oublié un argument ? Ajouté un argument ? Modifié quelques arguments ?</p>
<pre><code> Error: The functor application is ill-typed.
These arguments:
Etiquette Sommet Arete
do not match these parameters:
functor (Sommet : SOMMET)(Arete : ARETE)} ->
1. The following extra argument is provided
Etiquette : sig type t = string end
2. Module Sommet matches the expected module type SOMMET
3. Module Arete matches the expected module type ARETE
</code></pre>
<p>De plus en utilisant des méthodes de <em>diffing</em> (comparaison, généralement utilisées dans les correcteurs orthographiques ou du <em>fuzzy searching</em>/recherche floue), le vérificateur de type est capable de trouver une erreur la plus probable même dans des cas complexes.</p>
<h3 id="toc-confusion-entre-module-et-module-types">Confusion entre module et module types</h3>
<p>Un des détails surprenants d’OCaml est que beaucoup d’objets ont leur espace de noms séparé, ce qui mène parfois à des erreurs entêtantes. Par exemple :</p>
<pre><code class="ocaml"><span class="k">module</span> <span class="k">type</span> <span class="nc">M</span> <span class="o">=</span> <span class="k">sig</span> <span class="k">type</span> <span class="n">t</span> <span class="k">end</span>
<span class="k">type</span> <span class="n">u</span> <span class="o">=</span> <span class="nn">M</span><span class="p">.</span><span class="n">t</span></code></pre>
<blockquote>
<p>Error: Unbound module M</p>
</blockquote>
<p>ce message en OCaml 4.10.0 semble s’obstiner à ne pas reconnaître l’existence de <code>M</code>.</p>
<p>Le véritable problème est que <code>M</code> n’est pas un module, et donc ne définit pas de types. Depuis la version 4.12.0, le message d’erreur reconnaît qu’il s’agit d’une confusion naturelle :</p>
<blockquote>
<p>Error: Unbound module M<br>
Hint: There is a module type named M, but module types are not modules</p>
</blockquote>
<h3 id="toc-une-explication-des-problèmes-de-régularité">Une explication des problèmes de régularité</h3>
<p>Parfois, les messages d’erreurs sont évidents pour leurs auteurs, et totalement obscurs sans le bon contexte.</p>
<p>C’était notamment le cas d’un des messages d’erreurs concernant les types récursifs non-réguliers. Si l’enchaînement des mots précédents ne vous parle pas, il y avait de grandes chances que ce message d’erreur vous laisse pantois :</p>
<pre><code class="ocaml"> <span class="k">type</span> <span class="o">(</span><span class="k">'</span><span class="n">a</span><span class="o">,</span><span class="k">'</span><span class="n">b</span><span class="o">)</span> <span class="n">x</span> <span class="o">=</span> <span class="o">[</span> <span class="o">`</span><span class="nc">X</span> <span class="k">of</span> <span class="o">(</span><span class="k">'</span><span class="n">b</span><span class="o">,</span><span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">y</span> <span class="o">]</span>
<span class="ow">and</span> <span class="o">(</span><span class="k">'</span><span class="n">a</span><span class="o">,</span><span class="k">'</span><span class="n">b</span><span class="o">)</span> <span class="n">y</span> <span class="o">=</span> <span class="o">[</span> <span class="o">`</span><span class="nc">Y</span> <span class="k">of</span> <span class="o">(</span><span class="k">'</span><span class="n">a</span><span class="o">,</span><span class="k">'</span><span class="n">b</span><span class="o">)</span> <span class="n">x</span> <span class="o">]</span></code></pre>
<blockquote>
<p>Error: In the definition of y, type ('b, 'a) x should be ('a, 'b) x</p>
</blockquote>
<p>Il commet en effet trois péchés cardinaux pour un message d’erreur : il propose un correctif faux, il ne parle pas du code visible par l’utilisateur mais du résultat d’un calcul invisible du compilateur, et il ne pointe pas vers la source de l’erreur.</p>
<p>Ce souci est corrigé, et OCaml 4.12.0 prend désormais le temps d’expliquer le problème :</p>
<blockquote>
<p>Error: This recursive type is not regular.<br>
The type constructor x is defined as<br>
type ('a, 'b) x<br>
but it is used as<br>
('b, 'a) x<br>
after the following expansion(s):<br>
('b, 'a) y = [ `Y of ('b, 'a) x ]<br>
All uses need to match the definition for the recursive type to be regular.</p>
</blockquote>
<p>Le message d’erreur est long. Cependant il explique non seulement la nature du problème (un type paramétré est utilisé de façon différente au sein d’un même groupe de définition récursif) mais aussi comment le vérificateur de type a découvert l’erreur.</p>
<h2 id="toc-améliorations-de-lexpérience-utilisateur">Améliorations de l’expérience utilisateur</h2>
<p>Il y a aussi beaucoup d’améliorations de taille plus modeste qui sont plus difficiles à catégoriser.<br>
Parmi celles qui ont retenu mon attention sur ces deux dernières versions, je peux citer :</p>
<h3 id="toc-statmemprof-profiler-la-mémoire-sur-des-programmes-en-production">Statmemprof : profiler la mémoire sur des programmes en production.</h3>
<p>Pour des langages à glaneur de cellules (GC) comme OCaml, l’allocation et la désallocation de mémoire est un axe à la fois important et assez invisible de la performance des programmes. Il peut donc être important de surveiller le travail du GC dans un programme pour évaluer des problèmes de performances, ou s’assurer qu’il n’y ait pas de fuite de mémoire dans un serveur tournant durant des années.</p>
<p>Dans les versions d’OCaml antérieures à 4.12, la bibliothèque Spacetime fournissait de tels outils de surveillance en continu de la mémoire.</p>
<p>Cependant analyser le travail du GC peut-être extrêmement coûteux aussi bien en termes de temps que d’espace. Et il était pratiquement impossible d’utiliser Spacetime dans un environnement de production à cause de ces coûts.</p>
<p>Statmemprof est une réponse à ces problématiques : il s’agit d’un outil de profilage statistique de l’allocation et de la désallocation de la mémoire. En s’autorisant à n’analyser qu’une partie des allocations et des désallocations, il devient possible de contrôler le coût de cette analyse de la mémoire et de la rendre négligeable. Intégrer cette analyse dans du code en production devient alors possible. On peut même s’autoriser à ajuster le comportement du programme en fonction de sa consommation mémoire actuelle.</p>
<h3 id="toc-des-noms-pour-les-warnings">Des noms pour les warnings</h3>
<p>Après 25 ans d’existence, OCaml a accumulé plusieurs dizaines d’avertissements (70 dans la version 4.13.0). Fort heureusement, la configuration de ces avertissements est souvent laissée soit au compilateur soit au système d’assemblage. Notamment, <code>dune</code>, le système d’assemblage de prédilection de la plupart des paquets opam, a un choix d’avertissements assez strict par défaut.</p>
<p>Il reste néanmoins pratique de pouvoir modifier cette configuration pour un fichier ou une fonction spécifique. Par exemple, on peut activer le warning <code>27</code> pour juste la fonction <code>f</code> avec :</p>
<pre><code class="ocaml"><span class="k">let</span> <span class="n">f</span> <span class="n">x</span> <span class="o">=</span> <span class="bp">()</span> <span class="o">[@@</span><span class="n">warning</span> <span class="s2">"+27"</span><span class="o">]</span></code></pre>
<p>Cependant, à la lecture, il n’est pas exactement évident de se rappeler l’objet de cet avertissement <code>27</code>. Cela d’autant plus lorsque l’avertissement est utilisé ponctuellement. La nouvelle mouture d’OCaml permet enfin de nommer ces avertissements :</p>
<pre><code class="ocaml"><span class="k">let</span> <span class="n">f</span> <span class="n">x</span> <span class="o">=</span> <span class="bp">()</span> <span class="o">[@@</span><span class="n">warning</span> <span class="s2">"+unused-var-strict"</span><span class="o">]</span></code></pre>
<h3 id="toc-et-la-stdlib-sagrandit">Et la Stdlib s’agrandit</h3>
<p>La bibliothèque standard voit arriver deux nouveaux modules liés aux threads :</p>
<ul>
<li>
<p><code>Atomic</code> : ce module est là pour préparer en douceur la compatibilité avec le <em>runtime</em> multi-cœur.</p>
<ul>
<li>
<code>Thread.Semaphore</code> : ce module offre une contrepartie au <code>Mutex</code> qui n’a pas besoin d’être verrouillé et déverrouillé dans le même fil d’exécution. </li>
</ul>
</li>
</ul>
<p>et un nouveau module de structure de données :</p>
<ul>
<li>
<code>Either</code> : il s’agit d’un module d’alternative générique (on a soit un <code>Left a</code> soit un <code>Right b</code>) qui est utile lorsque nommer explicitement les deux alternatives serait pénible.</li>
</ul>
<p>Fut un temps, la bibliothèque standard d’OCaml avait pour objectif de rester assez minimaliste. Ce choix a engendré la création d’au moins quatre bibliothèques étendant la bibliothèque standard (extlib, batteries, base, containers). Cependant depuis, OCaml 4.07 la bibliothèque standard s’est ouverte à plus d’améliorations. Néanmoins, l’évolution de la bibliothèque standard reste basée sur un principe de quasi-unanimité, son rythme d’évolution reste donc très mesuré.</p>
<h3 id="toc-des-piles-dappels-plus-expressives">Des piles d’appels plus expressives</h3>
<p>Lorsque qu’une fonction lève une exception qui n’est pas attrapée, la pile d’appel (<em>backtrace</em>) contient désormais des informations sur les noms des fonctions qui se sont retrouvées sur la pile d’appel. Par exemple exécuter :</p>
<pre><code class="ocaml"> <span class="k">let</span> <span class="bp">()</span> <span class="o">=</span>
<span class="k">let</span> <span class="n">f</span> <span class="bp">()</span> <span class="o">=</span>
<span class="k">let</span> <span class="n">g</span> <span class="bp">()</span> <span class="o">=</span> <span class="k">raise</span> <span class="nc">Exit</span> <span class="k">in</span>
<span class="k">fun</span> <span class="bp">()</span> <span class="o">-></span> <span class="n">g</span> <span class="bp">()</span>
<span class="k">in</span>
<span class="n">f</span> <span class="bp">()</span> <span class="bp">()</span></code></pre>
<p>nous informe que</p>
<blockquote>
<p>Raised at Backtrace_example.f.g in file "backtrace_example.ml" (inlined), line 3, characters 16-26</p>
</blockquote>
<p>plutôt que le laconique</p>
<blockquote>
<p>Raised at file "backtrace_example.ml" (inlined), line 3, characters 16-26</p>
</blockquote>
<h2 id="toc-plus-de-types-pour-les-utilisateurs-experts">Plus de types pour les utilisateurs experts</h2>
<p>Le système s’est aussi enrichi de fonctionnalités plus orientées vers les auteurs de bibliothèques, et les utilisateurs experts.</p>
<h3 id="toc-des-noms-pour-les-types-existentiels">Des noms pour les types existentiels</h3>
<p>Les types existentiels sont une des fonctionnalités nouvelles apportées par les Types de Données Algébriques Généralisés (GADTs). Pour faire simple, il s’agit de types qui n’existent qu’à l’intérieur d’un constructeur.</p>
<p>Par exemple, je peux décrire une pipeline de transformation de <code>'a</code> vers <code>b</code> en plusieurs étapes :</p>
<pre><code class="ocaml"><span class="k">type</span> <span class="o">(</span><span class="k">'</span><span class="n">entree</span><span class="o">,</span><span class="k">'</span><span class="n">sortie</span><span class="o">)</span> <span class="n">pipeline</span> <span class="o">=</span>
<span class="o">|</span> <span class="nc">Vide</span><span class="o">:</span> <span class="o">(</span><span class="k">'</span><span class="n">entree</span><span class="o">,</span><span class="k">'</span><span class="n">entree</span><span class="o">)</span> <span class="n">pipeline</span>
<span class="o">|</span> <span class="nc">Etape</span><span class="o">:</span> <span class="o">(</span><span class="k">'</span><span class="n">entree</span><span class="o">,</span><span class="k">'</span><span class="n">intermediaire</span><span class="o">)</span> <span class="n">pipeline</span> <span class="o">*</span> <span class="o">(</span><span class="k">'</span><span class="n">intermediaire</span> <span class="o">-></span> <span class="k">'</span><span class="n">sortie</span><span class="o">)</span>
<span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">entree</span><span class="o">,</span><span class="k">'</span><span class="n">sortie</span><span class="o">)</span> <span class="n">pipeline</span></code></pre>
<p>Ici le constructeur <code>Etape</code> prend comme argument un pipeline de <code>entree</code> vers un type <code>intermediaire</code>, et une fonction de ce type <code>intermediaire</code> vers le type <code>sortie</code> et me donne en retour un pipeline de l’entrée vers la sortie.</p>
<p>Le point intéressant avec définition est que ce type intermédiaire n’est pas un type concret connu. Il s’agit d’un type inconnu dont je sais seulement qu’il est partagé par ma pipeline interne, et ma fonction de transformation.</p>
<p>Une bonne façon de voir comment ce type se comporte est d’implémenter une fonction <code>envoyer</code> qui applique toutes les étapes de la pipeline à une entrée et obtient une sortie.</p>
<pre><code class="ocaml"> <span class="k">let</span> <span class="k">rec</span> <span class="n">envoyer</span><span class="o">:</span> <span class="k">type</span> <span class="n">entree</span> <span class="n">sortie</span><span class="o">.</span> <span class="o">(</span><span class="n">entree</span><span class="o">,</span><span class="n">sortie</span><span class="o">)</span> <span class="n">pipeline</span> <span class="o">-></span> <span class="n">entree</span> <span class="o">-></span> <span class="n">sortie</span> <span class="o">=</span>
<span class="k">fun</span> <span class="n">pipeline</span> <span class="n">entree</span> <span class="o">-></span>
<span class="k">match</span> <span class="n">pipeline</span> <span class="k">with</span>
<span class="o">|</span> <span class="nc">Vide</span> <span class="o">-></span> <span class="n">entree</span>
<span class="o">|</span> <span class="nc">Etape</span><span class="o">(</span><span class="n">pipeline_interne</span><span class="o">,</span> <span class="n">transformation_finale</span><span class="o">)</span> <span class="o">-></span>
<span class="n">entree</span> <span class="o">|></span> <span class="n">envoyer</span> <span class="n">pipeline_interne</span> <span class="o">|></span> <span class="n">transformation_finale</span>
<span class="c">(* [x |> f] signifie [f x] *)</span></code></pre>
<p>Ici, tout ce passe bien. Mais que se passe-t-il si j’essaye d’appliquer la transformation finale avant le reste de la pipeline ?</p>
<pre><code class="ocaml"><span class="k">let</span> <span class="k">rec</span> <span class="n">envoyer_erronee</span><span class="o">:</span> <span class="k">type</span> <span class="n">entree</span> <span class="n">sortie</span><span class="o">.</span> <span class="o">(</span><span class="n">entree</span><span class="o">,</span><span class="n">sortie</span><span class="o">)</span> <span class="n">pipeline</span> <span class="o">-></span> <span class="n">entree</span> <span class="o">-></span> <span class="n">sortie</span> <span class="o">=</span>
<span class="k">fun</span> <span class="n">pipeline</span> <span class="n">entree</span> <span class="o">-></span>
<span class="k">match</span> <span class="n">pipeline</span> <span class="k">with</span>
<span class="o">|</span> <span class="nc">Vide</span> <span class="o">-></span> <span class="n">entree</span>
<span class="o">|</span> <span class="nc">Etape</span><span class="o">(</span><span class="n">pipeline_interne</span><span class="o">,</span> <span class="n">transformation_finale</span><span class="o">)</span> <span class="o">-></span>
<span class="n">entree</span> <span class="o">|></span> <span class="n">transformation_finale</span> <span class="o">|></span> <span class="n">envoyer</span> <span class="n">pipeline_interne</span></code></pre>
<p>J’obtiens une erreur de compilation qui se plaint que le type de <code>entree</code> n’est pas le bon :</p>
<blockquote>
<p>Error: This expression has type entree but an expression was expected of type<br>
$Etape_'intermediaire</p>
</blockquote>
<p>Et en effet, le code est faux parce que le type <code>entree</code> ne correspond pas au type attendu par la transformation finale. Le nom du type attendu <code>$Etape_'intermediaire</code> est cependant assez complexe.</p>
<p>Il s’agit d’un nom automatiquement généré pour un type existentiel à partir de la définition de type et du constructeur qui l’a introduit. Ici le nom est assez clair, mais dans des cas complexes ces noms générés automatiquement peuvent être <a href="https://ocaml.org/releases/4.12/manual/gadts.html#p:existential-names">difficiles à déchiffrer</a>. Une des nouveautés dans 4.13.0 est qu’il est désormais possible de nommer soi-même les types existentiels introduits dans le filtrage de motif:</p>
<pre><code class="ocaml"><span class="k">let</span> <span class="k">rec</span> <span class="n">envoyer_erronee</span><span class="o">:</span> <span class="k">type</span> <span class="n">entree</span> <span class="n">sortie</span><span class="o">.</span> <span class="o">(</span><span class="n">entree</span><span class="o">,</span><span class="n">sortie</span><span class="o">)</span> <span class="n">pipeline</span> <span class="o">-></span> <span class="n">entree</span> <span class="o">-></span> <span class="n">sortie</span> <span class="o">=</span>
<span class="k">fun</span> <span class="n">pipeline</span> <span class="n">entree</span> <span class="o">-></span>
<span class="k">match</span> <span class="n">pipeline</span> <span class="k">with</span>
<span class="o">|</span> <span class="nc">Vide</span> <span class="o">-></span> <span class="n">entree</span>
<span class="o">|</span> <span class="nc">Etape</span> <span class="o">(</span><span class="k">type</span> <span class="n">intermediaire</span><span class="o">)</span>
<span class="o">(</span><span class="n">pipeline_interne</span><span class="o">,</span> <span class="n">transformation_finale</span><span class="o">:</span>
<span class="o">(</span><span class="n">entree</span><span class="o">,</span> <span class="n">intermediaire</span><span class="o">)</span> <span class="n">pipeline</span> <span class="o">*</span> <span class="o">(</span><span class="n">intermediaire</span> <span class="o">-></span> <span class="n">sortie</span><span class="o">)</span>
<span class="o">)</span> <span class="o">-></span>
<span class="n">entree</span> <span class="o">|></span> <span class="n">transformation_finale</span> <span class="o">|></span> <span class="n">envoyer</span> <span class="n">pipeline_interne</span></code></pre>
<p>Cette fois-ci, le message d’erreur utilise notre nom de type :</p>
<blockquote>
<p>Error: This expression has type entree but an expression was expected of type<br>
intermediaire</p>
</blockquote>
<p>Ce qui devrait réduire légèrement le temps passé à faire compiler du code utilisant fortement les <a href="https://en.wikipedia.org/wiki/Generalized_algebraic_data_type">GADT</a>. Cette notation permet aussi d’obtenir facilement le type abstrait correspondant au type existentiel pour lequel il y a des applications plus élaborées.</p>
<h3 id="toc-de-linjectivité-pour-vos-types">De l’injectivité pour vos types</h3>
<p>Les bibliothèques vont pouvoir ajouter des points d’exclamation à leurs types</p>
<pre><code class="ocaml"><span class="k">type</span> <span class="o">!</span><span class="k">'</span><span class="n">a</span> <span class="n">vec</span></code></pre>
<p>pour indiquer que le paramètre <code>'a</code> est vraiment utilisé dans le type et n’est pas un type fantôme.<br>
Cela permet de débloquer certains usages avancés des GADT où il est vital de savoir si <code>int vec</code> et forcément différent de <code>float vec</code>. </p>
<p>Par exemple, avec cette annotation, le vérificateur de type sait qu’avec la définition suivante :</p>
<pre><code class="ocaml"><span class="k">type</span> <span class="o">_</span> <span class="n">int_or_float_vec</span> <span class="o">=</span>
<span class="o">|</span> <span class="nc">Int_vec</span> <span class="o">:</span> <span class="kt">int</span> <span class="n">vec</span> <span class="o">-></span> <span class="kt">int</span> <span class="n">vec</span> <span class="n">int_or_float_vec</span>
<span class="o">|</span> <span class="nc">Float_vec</span><span class="o">:</span> <span class="kt">float</span> <span class="n">vec</span> <span class="o">-></span> <span class="kt">float</span> <span class="n">vec</span> <span class="n">int_or_float_vec</span></code></pre>
<p>lorsqu’on a une valeur de type <code>'a int_or_float_vec</code>, la variable <code>'a</code> est forcément soit <code>int vec</code> soit <code>float vec</code>. En d’autres mots, on ne peut jamais se procurer une valeur de type <code>char int_or_float_vec</code> :</p>
<pre><code class="ocaml"><span class="k">let</span> <span class="n">impossible</span><span class="o">:</span> <span class="kt">char</span> <span class="n">int_or_float_vec</span> <span class="o">-></span> <span class="o">_</span> <span class="o">=</span> <span class="k">function</span> <span class="o">_</span> <span class="o">-></span> <span class="o">.</span></code></pre>
<p>Sans cette annotation, le vérificateur de type ne peut éliminer la possibilité que le type <code>'a vec</code> ait été défini en tant que synonyme de <code>char</code>:</p>
<pre><code class="ocaml"><span class="k">type</span> <span class="k">'</span><span class="n">a</span> <span class="n">vec</span> <span class="o">=</span> <span class="kt">char</span></code></pre>
<p>Comme pour les annotations de variances, l’injectivité est automatiquement inférée pour les types non-abstraits. Ces annotations sont donc essentiellement là pour les auteurs de bibliothèque.</p>
<h2 id="toc-au-delà-docaml-multi-cœur">Au-delà d’OCaml multi-cœur</h2>
<p>Si l’implémentation d’OCaml multi-cœur se rapproche lentement mais inexorablement, les plans pour le futur d’OCaml ne s’arrêtent pas là. </p>
<p>En particulier, la gestion de la concurrence et du parallélisme sera à terme basée sur un système d’effets. La prochaine étape de ce côté sera de concevoir et déployer un système d’effets typés facile à utiliser en pratique. </p>
<p>Mais le développement d’OCaml 5 ne se concentrera pas uniquement sur l’aspect multi-cœur. Une des forces d’OCaml est son système de modules à la fois expressif et adapté à la compilation séparée. Cependant, cette puissance a un prix, et les usages avancés du système de modules peuvent être particulièrement lourds syntaxiquement. Un des projets en cours pour OCaml 5 est d’introduire des méthodes plus légères pour décrire des fonctions paramétrées par des modules, à travers un système de foncteurs légers et implicites.</p>
</div><div><a href="https://linuxfr.org/news/ocaml-en-2021.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/122909/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/ocaml-en-2021#comments">ouvrir dans le navigateur</a>
</p>
octachronYves BourguignonchimrodYsabeau 🧶 🧦SnarkBenoît SibaudAnonymeBruno EthvignotQuidamtisaacMichaëldourouc05syntaxerrorhttps://linuxfr.org/nodes/122909/comments.atomtag:linuxfr.org,2005:Bookmark/35192021-08-30T17:39:11+02:002021-08-30T17:39:11+02:00Xavier Leroy : les 25 ans de Ocaml<a href="https://watch.ocaml.org/videos/watch/e1ee0fc0-50ef-4a1c-894a-17df181424cb">https://watch.ocaml.org/videos/watch/e1ee0fc0-50ef-4a1c-894a-17df181424cb</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/125266/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/thoasm/liens/xavier-leroy-les-25-ans-de-ocaml#comments">ouvrir dans le navigateur</a>
</p>
Thomas Douillardhttps://linuxfr.org/nodes/125266/comments.atomtag:linuxfr.org,2005:Bookmark/34902021-08-23T20:03:49+02:002021-08-23T20:03:49+02:00Alors comme ça, Bloomberg, vous utilisez du OCaml en prod pour des trucs sérieux ?<a href="https://twitter.com/adolfont/status/1429759258942377999">https://twitter.com/adolfont/status/1429759258942377999</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/125205/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/vendrediouletrollsauvage/liens/alors-comme-ca-bloomberg-vous-utilisez-du-ocaml-en-prod-pour-des-trucs-serieux#comments">ouvrir dans le navigateur</a>
</p>
voltshttps://linuxfr.org/nodes/125205/comments.atomtag:linuxfr.org,2005:Bookmark/30512021-05-09T18:47:31+02:002021-05-09T18:47:31+02:0025 years of OCaml<a href="https://discuss.ocaml.org/t/25-years-of-ocaml/7813">https://discuss.ocaml.org/t/25-years-of-ocaml/7813</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/124223/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/benoit_in/liens/25-years-of-ocaml#comments">ouvrir dans le navigateur</a>
</p>
Benoît Laurenthttps://linuxfr.org/nodes/124223/comments.atomtag:linuxfr.org,2005:Diary/394422020-11-13T15:51:50+01:002020-11-13T15:51:50+01:00Retour d'expérience sur les langages de programmationLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#toc-petit-tour-dexp%C3%A9rience-sur-des-langages">Petit tour d'expérience sur des langages</a><ul>
<li><a href="#toc-ocaml">OCaml</a></li>
<li><a href="#toc-haskell">Haskell</a></li>
<li><a href="#toc-tcl-perl-python-raku">Tcl, Perl, Python, Raku</a></li>
<li><a href="#toc-common-lisp-racket">Common Lisp, Racket</a></li>
<li><a href="#toc-j">J</a></li>
<li><a href="#toc-coq">Coq</a></li>
<li><a href="#toc-go">Go</a></li>
<li><a href="#toc-rust">Rust</a></li>
</ul>
</li>
<li><a href="#toc-ce-quil-mest-rest%C3%A9-de-tout-%C3%A7a">Ce qu'il m'est resté de tout ça</a></li>
<li><a href="#toc-langages-que-jaimerais-creuser-un-peu-un-jour">Langages que j'aimerais creuser un peu un jour</a></li>
</ul>
<p>Ces derniers temps, j'apprends moins de langages nouveaux qu'il y a quelques années. Du coup, je me suis dit que c'était une occasion de faire le tour sur l'essentiel des langages que j'ai testés.</p>
<p>Dans ce journal, je fais un peu dans le classique du ceci ou cela m'a plu dans tel langage, telle autre chose ne m'a pas plu. Le tout est très subjectif, biaisé et reflète fortement les trucs que j'ai voulu faire avec ces langages. Mais bon, j'ai lu beaucoup d'articles de blog dans ce genre (enfin, en général sur un seul langage, ou L1 vs L2) et, même si ça n'aide pas souvent à découvrir le langage de nos rêves, ni à changer d'opinion ou à apprendre grand-chose sur un langage qu'on connait déjà, j'ai trouvé quand même ça souvent sympa à lire vite fait, même (voire surtout) quand mon ressenti est différent.</p>
<h2 id="toc-petit-tour-dexpérience-sur-des-langages">Petit tour d'expérience sur des langages</h2>
<h3 id="toc-ocaml">OCaml</h3>
<p><a href="https://fr.wikipedia.org/wiki/OCaml">OCaml</a> est le premier langage que j'ai appris ! (enfin, son prédécesseur Camllight initialement, le langage qui était utilisé qu'en prépas en France)</p>
<p>Les trucs que j'ai aimés :</p>
<ul>
<li>Compile vers du code natif assez efficace.</li>
<li>Typage expressif (<a href="https://fr.wikipedia.org/wiki/Type_alg%C3%A9brique_de_donn%C3%A9es">types algébriques</a>), mais pratique (<a href="https://fr.wikipedia.org/wiki/Inf%C3%A9rence_de_types">inférence de types</a>) et pas trop compliqué : langage abordable.</li>
<li>Mélange de code fonctionnel et impératif possible et plutôt facile.</li>
<li>Sympa pour manipuler des structures de données arborescentes. En particulier pour écrire des analyses ou transformations d'AST.</li>
<li>Documentation accessible en ligne de commande.</li>
</ul>
<p>Les trucs qui me laissent dubitatif :</p>
<ul>
<li>Des messages d'erreur qui se sont améliorés mais, le typage riche et l'inférence n'aidant pas, les erreurs ont toujours du mal à parler la langue des mortels.</li>
<li>Une syntaxe et un système de types pas trop compliqués, mais qui se compliquent ces dernières années : introduction des GADT (une sorte de types dépendants — en gros, des monstres surpuissants invoqués par des super héros) et les extensions de syntaxe ppx qui peuvent casser à chaque changement de version, entres autres; ça a du bon quand même.</li>
<li>La syntaxe : l'extension <a href="https://reasonml.github.io/">Reason</a> fait plus de modifications que strictement nécessaire, mais marquer clairement la fin des <em>pattern matching</em> et autres structures de contrôle (comme en Rust), ce serait déjà bien (après, des accolades ou un <code>end</code> comme en Coq ou Ruby, c'est du détail).</li>
<li>Pas besoin de préciser les bibliothèques utilisées en préambule de fichier.</li>
<li>Un nombre ok de bibliothèques tierces.</li>
</ul>
<p>Les trucs que j'ai moins aimés :</p>
<ul>
<li>Bibliothèque standard limitée, beaucoup de variantes de fonctions de base, mais peu au-delà (pas de compression, encodage, unicode, http). Au moins deux bibliothèques alternatives existent, mais elles résolvent surtout des soucis différents.</li>
<li>Exceptions, en particulier leur sur-utilisation dans la bibliothèque standard qui a conduit à l'introduction de variantes en <code>*_opt</code> renvoyant plutôt un type option, du genre <code>None</code> ou <code>Some x</code>, plutôt que <code>Not_found</code> (mais pas pour toutes les fonctions encore).</li>
<li>Manque de structures de contrôle impératives : pas de break, continue, return ; ça peut vite devenir gênant si on manipule beaucoup les tableaux (tableaux qui d'ailleurs gagneraient en ergonomie à être dynamiques).</li>
<li>Des fonctions non <a href="https://fr.wikipedia.org/wiki/R%C3%A9cursion_terminale">récursives terminales</a> (donc risque de débordement de pile) dans la bibliothèque standard qui ont conduit à plus de duplication avec l'introduction de fonctions récursives terminales équivalentes.</li>
<li>Les bibliothèques, à moins d'être très populaires, risquent d'être mal documentées : les types des fonctions, si on a de la chance une courte description pour chacune, parfois un exemple dans le README.</li>
<li>Certaines bibliothèques connues font dans l'ingénierie lourde (comme le framework <a href="https://ocsigen.org/home/intro.html">ocsigen</a>), pas toujours évident de trouver des alternatives plus simples et bien documentées.</li>
</ul>
<h3 id="toc-haskell">Haskell</h3>
<p><a href="https://fr.wikipedia.org/wiki/Haskell">Haskell</a> a des propriétés similaires à OCaml, à ceci près qu'il accueille avec joie la complexité. Plus amusant, mais plus frustrant aussi.</p>
<p>Les trucs que j'ai aimés :</p>
<ul>
<li>Compile vers du code natif assez efficace.</li>
<li>Typage expressif, inférence de type.</li>
<li>Comme OCaml, pratique pour la manipulation d'AST.</li>
<li>La bibliothèque [parsec](<a href="https://en.wikipedia.org/wiki/Parsec_(parser)">https://en.wikipedia.org/wiki/Parsec_(parser)</a> qui permet de parser en combinant des parseurs. Des alternatives dans d'autres langages ont vu le jour, mais parsec reste plus naturel (mais pas le plus performant par contre).</li>
</ul>
<p>Les trucs qui me laissent dubitatif :</p>
<ul>
<li>Les <a href="https://en.wikipedia.org/wiki/Monad_(functional_programming)">monades</a>, des abstractions qui permettent de structurer les programmes de façon générique. C'est utilisé dans parsec pour combiner naturellement des parseurs, par exemple. Les monades IO et ST permettent de faire de l'impératif de façon compliquée aussi. C'est aussi utilisé pour rendre certains tutoriels très abstraits.</li>
<li>Un système de types plus complexe que celui d'OCaml et qui rencontre plus tôt les limites de l'inférence. Et une pléthore d'extensions de langage optionnelles.</li>
<li>Des messages d'erreur pour initiés à cause du typage expressif et de l'inférence de types.</li>
<li>Une communauté intéressée par des concepts comme les monades, les flèches, les catégories, etc. Ça se reflète dans de nombreux tutoriels et échanges, tout comme dans les bibliothèques tierces. C'est plus dur de trouver des contenus qui font dans le pragmatique. Ce point devient positif si on est passionné par les concepts mentionnés, ou source de frustration autrement :-)</li>
<li>Je n'aime pas trop certains éléments de syntaxe : l'indentation significative, l'abondance d'opérateurs avec priorités et associativité variables.</li>
<li>Des préambules de fichier avec souvent une suite interminable d'imports de bibliothèques et un mélange d'imports avec noms qualifiés et non qualifiés.</li>
</ul>
<p>Les trucs que j'ai moins aimés :</p>
<ul>
<li>Compilation lente.</li>
<li>Possible mais difficile de faire de l'impératif : manipuler des tableaux est tout sauf agréable (par exemple pour représenter la carte dans un jeu, faire de la recherche de chemins, etc.).</li>
<li>Il faut utiliser une bibliothèque externe pour avoir des chaînes de caractères implémentées raisonnablement.</li>
<li>Beaucoup de bibliothèques, mais c'est pas facile de s'y retrouver.</li>
<li>Beaucoup de bibliothèques font dans l'ingénierie lourde.</li>
<li>Beaucoup de bibliothèques ont un arbre conséquent de dépendances. </li>
<li>Beaucoup de bibliothèques sont mal documentées.</li>
</ul>
<p>Exemple personnel : recherche d'une bibliothèque pour gérer le xml. Première tentative, <a href="https://hackage.haskell.org/package/hxt">hxt</a> : pas moyen de trouver un indice dans la doc sur comment commencer (le théoricien remarquera que ça s'inspire de la <a href="https://fr.wikipedia.org/wiki/Morphisme">théorie des flèches</a>, mais ça l'aidera pas forcément tant que ça non plus). Deuxième tentative, <a href="https://hackage.haskell.org/package/HaXml-1.25.5/docs/Text-XML-HaXml.html">HaXml</a> : un peu moins abstrait peut-être, mais bon courage quand même. Troisième tentative, <a href="https://hackage.haskell.org/package/xml-1.3.14/docs/Text-XML-Light.html">Text-XML-Light</a>, le nom semble prometteur : pas d'exemples, mais ça semble en effet plus simple. Si l'on n'a pas encore capitulé, c'est le moment de chercher s'il n'y a pas un tutoriel à peu près à jour quelque part dans le wiki du langage pour une de ces bibliothèques.</p>
<p>Ceci dit, Haskell, c'est vraiment l'occasion de découvrir des concepts théoriques en faisant des trucs concrets, du genre découvrir à l'aide d'un framework web (appelé snap si ma mémoire est bonne) que les lentilles c'est pas seulement un truc qui se mange.</p>
<h3 id="toc-tcl-perl-python-raku">Tcl, Perl, Python, Raku</h3>
<p>Tous ces langages se ressemblent un peu : typage dynamique, bases faciles à apprendre, plus ou moins d'OO, communauté pragmatique avec des écosystèmes de packages très variés, langages pas super performants mais suffisamment dans beaucoup de cas. Du coup, je vais parler uniquement des choses marquantes qui m'ont semblé uniques à chacun.</p>
<p>Pour Perl :</p>
<ul>
<li>Intégration des expressions régulières dans le langage, inspirée de <a href="https://fr.wikipedia.org/wiki/Stream_Editor">Sed</a> : erreurs dans la regexp à la compilation, plein de fonctionnalités sur l'Unicode.</li>
<li>Mode de traitement de texte inspiré de <a href="https://fr.wikipedia.org/wiki/Awk">Awk</a> et adapté aux traitements rapides en ligne de commande.</li>
<li>Une documentation commode en ligne de commande et qui permet de démarrer vite, avec beaucoup d'exemples dans un style un peu « recettes » en synopsis.</li>
<li>Quelques incantations répétitives à écrire en début de chaque fichier.</li>
<li>Un peu plus fonctionnel (fonctions anonymes, portée lexicale des variables).</li>
<li>Mini typage statique partiel (scalaires vs tableaux vs tables de hachage, typos dans les noms de variables attrapées lors de la compilation).</li>
</ul>
<p>Pour Python :</p>
<ul>
<li>Beaucoup de bibliothèques dans le domaine du calcul scientifique (numpy, etc.).</li>
<li>Documentation plus OO que celle de Perl, plus orientée web que ligne de commande.</li>
<li>
<a href="https://fr.wikipedia.org/wiki/Liste_en_compr%C3%A9hension">Listes en
compréhension</a>
(perso, j'aime pas trop, ça se démarque un peu du reste du langage).</li>
</ul>
<p>Pour <a href="https://fr.wikipedia.org/wiki/Tool_Command_Language">Tcl</a> :</p>
<ul>
<li>Syntaxe où « tout est chaîne de caractères et commandes », mais fait proprement et sans pièges, contrairement au shell. Ça permet de faire des DSLs très naturels.</li>
<li>Par exemple, l'intégration très sympa avec SQLite : on peut écrire <code>db eval {SELECT uid FROM table WHERE n <= $max AND time < $epoch}</code> en mettant directement les variables <code>$max</code> et <code>$epoch</code> dans la requête sans risquer d'injections SQL (c'est pas de l'interpolation en fait). Ça évite la typique redondance où il faut passer les arguments à la requête après, souvent avec le même nom.</li>
<li>Plus fragile aux typos que Perl ou Python.</li>
<li>Intégration très naturelle avec Tk : mon langage préféré pour les petits GUI couplé à SQLite.</li>
<li>Documentation sous forme de pages de manuel proches de celles des outils en ligne de commande : plus formelle que la documentation Perl.</li>
<li>Wiki communautaire plein d'exemples, mais un peu chaotique.</li>
<li>Écosystème plus petit que les autres : pas idéal pour faire du calcul scientifique, par exemple, et moins de choix en général (par exemple pour faire du web).</li>
<li>Malgré son caractère de langage généraliste et bibliothèque standard assez vaste, Tcl peut être aussi facilement utilisé comme langage d'extension d'un programme en C (à la Lua).</li>
</ul>
<p>Pour <a href="https://fr.wikipedia.org/wiki/Raku_(langage)">Raku</a> (anciennement Perl 6) :</p>
<ul>
<li>Langage généraliste à tout faire très (trop ?) ambitieux et pas effrayé par la complexité.</li>
<li>Langage plutôt cohérent et orthogonal, inspiré de Perl (mais aussi Ruby et d'autres), mais plus OO dans l'esprit.</li>
<li>Les messages d'erreur sont plutôt sympas.</li>
<li>Les expressions régulières sont intégrées dans un concept plus vaste de grammaires, très pratique pour écrire des parseurs.</li>
<li>La VM se lance un peu lentement et les modules compilent pas vite non plus.</li>
<li>Les expressions régulières, qui sont quand même fondamentales dans ce langage, étaient encore très mal optimisées il y a un ou deux ans, la dernière fois que j'ai testé.</li>
<li>L'écosystème est assez jeune encore.</li>
</ul>
<h3 id="toc-common-lisp-racket">Common Lisp, Racket</h3>
<p><a href="https://fr.wikipedia.org/wiki/Common_Lisp">Common Lisp</a> et <a href="https://fr.wikipedia.org/wiki/Racket_(langage)">Racket</a> sont des langages fonctionnels, par défaut au typage dynamique, ils se prêtent très bien à la manipulation de structures arborescentes et sont très prisés pour leur extensibilité à l'aide de systèmes de macros évolués. Les deux ont pas mal de bibliothèques tierces et compilent vers du code assez efficace (normalement moins que OCaml ou Haskell, mais nettement plus que Python ou Perl).</p>
<p>Pour Racket :</p>
<ul>
<li>Une documentation plus propre, surtout pour les bibliothèques tierces. Pour tout dire, lorsque j'ai testé, j'étais émerveillé par <a href="https://docs.racket-lang.org/scribble/index.html">scribble</a>, leur langage de documentation, qui est un dialecte de racket lui-même et permet de faire plein de validations sur la doc, dont le fait que les exemples compilent et renvoient le bon truc.</li>
<li>Plus orienté fonctionnel, mais aussi plus académique : une partie de l'objectif du langage est d'illustrer les recherches en théorie des langages extensibles.</li>
<li>Démarrage plus lent de la VM.</li>
</ul>
<p>Pour Common Lisp :</p>
<ul>
<li>Macros plus simples, mais non <a href="https://en.wikipedia.org/wiki/Hygienic_macro">hygiéniques</a> (ce qui est pas cool par les temps qui courent).</li>
<li>Un peu plus fonctionnel, en particulier la construction extrêmement flexible <code>loop</code>, ou peut-être encore mieux, la bibliothèque <a href="https://common-lisp.net/project/iterate/">iterate</a> : une macro d'itération très extensible !</li>
<li>Un peu le bazar pour ce qui est des bibliothèques tierces : le gestionnaire de paquets lui-même, bien que fonctionnel, est considéré bêta depuis très très longtemps.</li>
</ul>
<p>Si l'on veut juste apprendre afin de découvrir les macros pour faire des DSLs, c'est bien plus simple de faire ça avec Tcl.</p>
<h3 id="toc-j">J</h3>
<p><a href="https://fr.wikipedia.org/wiki/J_(langage)">J</a> est un langage fonctionnel de manipulation vectorisée de tableaux multi-dimensionnels avec une syntaxe compacte faisant usage de primitives de haut niveau. C'est une variante moderne d'<a href="https://fr.wikipedia.org/wiki/APL_(langage)">APL</a> avec une syntaxe ASCII et plus de fonctionnalités.</p>
<p>Les trucs que j'ai aimés :</p>
<ul>
<li>La notation compacte est sympa pour expérimenter dans l'invite de commande.</li>
<li>Les primitives du langage sont très génériques et flexibles.</li>
<li>C'est amusant et ça fait réfléchir différemment à certains problèmes : je me suis amusé par exemple avec les problèmes du project euler, la génération de cartes et algos de dijkstra, ou l'écriture d'un automate pour parser des poèmes.</li>
</ul>
<p>Les trucs que j'ai moins aimés :</p>
<ul>
<li>Lorsqu'un algorithme ne se prête pas bien à une vectorisation, ça devient un casse-tête infernal.</li>
<li>J'ai beaucoup de mal à lire le code écrit par les autres.</li>
<li>De manière générale, j'ai l'impression que ce langage a tendance à facilement faire saturer ma mémoire cognitive de travail : un langage idéal pour quand j'ai besoin de me sentir idiot, ça marche à chaque fois.</li>
<li>Pour tout le code non algorithmique d'un projet, c'est aussi verbeux que n'importe quel langage et on ressent l'absence de structs/maps.</li>
</ul>
<p>Le langage est surtout utilisé en statistiques et calcul scientifique, mais je dois dire que si j'avais un besoin dans ce domaine, je chercherais plutôt du côté de Python, <a href="https://fr.wikipedia.org/wiki/R_(langage_de_programmation_et_environnement_statistique)">R</a> ou <a href="https://fr.wikipedia.org/wiki/Julia_(langage)">Julia</a>. J'utilise J parfois comme calculatrice. En pratique je me contente souvent de la calculatrice <code>dc</code> du standard POSIX :-)</p>
<h3 id="toc-coq">Coq</h3>
<p><a href="https://coq.inria.fr/">Coq</a> est un assistant de preuve et un langage purement fonctionnel que j'ai pas mal utilisé pendant la thèse dans le domaine de la compilation. Je suis resté simple utilisateur, assez ignorant des théories derrière et des techniques avancées d'automatisation de preuve. Il y a eu <a href="//linuxfr.org/news/sortie-de-coq-8-5-beta-un-assistant-de-preuve-formelle">une dépêche</a> ici il y a quelques années par des gens qui connaissent bien mieux le truc (perso, j'avais juste contribué avec un exemple).</p>
<p>Les trucs que j'ai aimés :</p>
<ul>
<li>C'est rigolo. Sérieusement, écrire des preuves de programme, c'est un peu comme un jeu, avec des moments de victoires épiques et de défaites accablantes.</li>
<li>C'est un langage avec un système de types extrêmement expressif : imaginez par exemple pouvoir écrire à l'aide du système de types qu'une passe d'optimisation d'un compilateur ne change pas la sémantique d'un programme et n'introduit donc pas de bugs inattendus !</li>
<li>Comme OCaml ou Haskell, le langage se prête bien à la manipulation d'AST et donc à l'écriture de compilateurs (avec des difficultés additionnelles ceci dit, comme le fait que les entiers sont représentés par un type algébrique et que Coq offre uniquement des structures de données purement fonctionnelles).</li>
</ul>
<p>Les trucs qui me laissent dubitatif :</p>
<ul>
<li>Écrire du code propre est relativement facile, mais des preuves propres, c'est une autre histoire : il y a l'approche où on essaie d'automatiser un maximum, ce qui demande de connaître très bien le langage de tactiques (donc preuve compréhensible par moins de monde), d'avoir une machine puissante (automatisation signifie plus de travail pour Coq) et compromettre la maintenabilité (du genre preuve qui passe plus avec la version suivante de Coq); il y a l'approche où on automatise pas trop et écrit beaucoup de lemmes intermédiaires et des preuves parfois répétitives, on insiste jusqu'à ce que ça passe à force de sentiments forts : je faisais partie des utilisateurs chevronnés de cette technique de jeu.</li>
</ul>
<p>Les trucs que j'ai moins aimés :</p>
<ul>
<li>Ça prend beaucoup de temps. Difficile de trouver des applications qui justifient cela, et ce même dans les domaines qui se prêtent assez bien à la preuve de programme (comme la compilation).</li>
<li>Il faut utiliser un autre langage, généralement OCaml, pour les parties non purement fonctionnelles du programme qui font de l'I/O.</li>
<li>C'est un langage complexe avec des messages d'erreur qui demandent une bonne expérience pour être appréhendés.</li>
<li>Faut pas s'attendre à trouver des contributeurs dans la nature : les programmeurs Coq se trouvent tous ou presque dans le domaine de la recherche.</li>
<li>Comme tout jeu, on finit par se lasser un peu à un moment et un jeu long dont on se lasse est un jeu qu'on ne finit pas (à moins d'être payé pour).</li>
<li>Les ressources disponibles dans la nature pour apprendre sont limitées, souvent écrites pour des gens qui font une thèse et sont intéressés par la théorie. La pratique et les astuces de preuve, faut les apprendre soi-même ou lors d'échanges avec les collègues si on a la chance d'être dans un environnement Coq. Bref, c'est peu accessible.</li>
</ul>
<h3 id="toc-go">Go</h3>
<p><a href="https://fr.wikipedia.org/wiki/Go_(langage)">Go</a> est un langage que j'utilise beaucoup ces derniers temps (frundis, jeux, des petits scripts), je suis plutôt satisfait.</p>
<p>Les trucs que j'ai aimés :</p>
<ul>
<li>Compile vers du code natif efficace. Compilation rapide, statique par défaut.</li>
<li>Langage : structures de contrôle impératives flexibles (for, switch, break, continue, labels de boucle), les essentiels du fonctionnel (fonctions de première classe et <a href="https://fr.wikipedia.org/wiki/Fermeture_(informatique)">clôtures lexicales</a>), l'essentiel de l'OO (structs, méthodes et interfaces, pas de classes), l'essentiel du typage statique (typage moyennement expressif, mais flexible au besoin et sans conversions implicites ni inférences trop génériques qui compliquent les messages d'erreur), l'essentiel des structures de données (maps et tableaux dynamiques, comme avec Perl, Python ou Ruby).</li>
<li>Une bibliothèque standard fournie, mais abordable et bien documentée.</li>
<li>Beaucoup de bibliothèques tierces bien documentées, souvent avec peu ou pas de dépendances.</li>
<li>Crosscompilation facile pour les programmes en pur Go (avec export en WebAssembly facile).</li>
<li>Programmation concurrente facile avec les channels et goroutines.</li>
<li>Un package, c'est tous les fichiers d'un dossier: pas besoin de faire un package différent pour éviter d'avoir trop de trucs dans un même fichier.</li>
<li>Documentation accessible en ligne de commande et, en général, langage pratique à utiliser dans un terminal avec plein d'outils (renommages, analyses statiques, bonne intégration vim/emacs, etc.).</li>
</ul>
<p>Les trucs qui me laissent dubitatif :</p>
<ul>
<li>URLs pour les noms d'import de package : ça conduit à devoir modifier le code si on change l'hébergement du projet. Ceci dit, le packaging n'a pas de solution magique non plus : j'ai beau ne pas vraiment aimer cette idée, c'est souvent pratique et pas clairement pire que les alternatives sur tous les points.</li>
<li>Absence de types génériques (<a href="https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md">en cours</a> d'être résolue, peut-être pour dans un an ou deux) : ça serait bien dans certains cas (bibliothèques génériques pour structures de données complexes ou opérations génériques sur des channels), mais ça me manque assez rarement tout compte fait (je ne ressens pas le besoin de remplacer les boucles <code>for</code> par des fonctions génériques, par exemple).</li>
<li>Plus verbeux qu'un langage dynamique, essentiellement du fait des signatures de fonctions (en pratique rentable dans un projet qui va au-delà du script, je trouve).</li>
</ul>
<p>Les trucs que j'ai moins aimés :</p>
<ul>
<li>Difficile parfois de faire du pur Go (GUI, SQLite, etc.) : l'avantage de la crosscompilation facile disparaît dans ce cas. C'est pas vraiment un point négatif, mais une annulation courante de point positif.</li>
</ul>
<h3 id="toc-rust">Rust</h3>
<p>Rust est un langage qui a pas mal de popularité en ce moment, <a href="//linuxfr.org/tags/rust/public">pas mal de trucs</a> sont passés sur linuxfr. J'ai lu un tutoriel, testé des exemples et lu de la doc, mais je n'ai jamais vraiment programmé avec, donc voici plutôt un retour d'apprentissage et d'utilisation :</p>
<ul>
<li>Des programmes très performants, dont le génial <a href="https://lib.rs/crates/ripgrep">ripgrep</a> qui remplace avantageusement grep.</li>
<li>Des programmes avec beaucoup de dépendances et qui mettent beaucoup de temps à compiler.</li>
<li>Langage d'inspirations multiples avec typage assez expressif (types somme et filtrage par motif similaires à OCaml), des <a href="https://en.wikipedia.org/wiki/Trait_(computer_programming)"><em>traits</em></a> (mais sans classes, un peu comme en Go).</li>
<li>Langage qui facilite l'impératif et le fonctionnel, même si l'absence de GC rend certaines pratiques de programmation fonctionnelle (comme une fonction qui renvoie une fonction) un peu alambiquées à écrire.</li>
<li>Un peu complexe à apprendre du fait de quelques notions assez subtiles (<a href="https://fr.wikipedia.org/wiki/Rust_(langage)#Possession_et_emprunt"><em>ownership</em>, <em>borrowing</em></a>) qui facilitent l'écriture de programmes concurrents <em>memory safe</em>, et du fait de l'ampleur du langage (macros, etc.).</li>
<li>Une documentation orientée web (même s'il me semble que j'avais trouvé un outil non officiel en ligne de commande).</li>
</ul>
<p>J'aimerais m'y mettre un jour, mais j'ai pas d'idée de projet personnel qui profite de l'absence de GC : un peu comme pour le C et le C++, avec la différence qu'avec ceux-ci je me suis déjà retrouvé à devoir lire voire modifier du code dans les programmes que j'utilise, et ça ne m'est pas encore arrivé avec du Rust.</p>
<h2 id="toc-ce-quil-mest-resté-de-tout-ça">Ce qu'il m'est resté de tout ça</h2>
<p>Au final, aujourd'hui, les seuls langages que j'utilise vraiment encore sont Go (pour un peu tout), Tcl (pour les GUIs et SQLite) et Perl (pour les petits scripts et <a href="https://fr.wikipedia.org/wiki/Comprehensive_Perl_Archive_Network">CPAN</a>). C'est sans compter des petits bouts de Javascript (dont j'ai pas parlé, car j'ai juste écrit des petits trucs en vanilla avec la doc de mozilla, sans aller chercher quoi que ce soit dans l'écosystème), ou les modifs de code C/C++ pour compiler sous OpenBSD, et mes tentatives le plus souvent couronnées d'échec pour compiler puis lancer du Java (dernière défaite cuisante en date : le jeu Mindustry qui est passé en dépêche il y a peu).</p>
<p>Ceci dit, même si au final on peut se dire à quoi bon avoir exploré autant de langages, j'ai bon souvenir de tout ça et ça influe probablement sur ma façon de programmer, j'espère qu'en bien :-)</p>
<h2 id="toc-langages-que-jaimerais-creuser-un-peu-un-jour">Langages que j'aimerais creuser un peu un jour</h2>
<p>Un langage relativement nouveau qui m'a l'air intéressant est <a href="https://www.nongnu.org/txr/">txr</a> : c'est en fait la combinaison de deux langages, un langage qui permet de capturer des motifs et parser facilement des documents, inspiré d'Awk, et un langage au style Lisp, mais différent. C'est pas un petit langage !</p>
<p>Dans le domaine des langages logiques, je trouve curieux <a href="https://fr.wikipedia.org/wiki/Mercury_(langage)">Mercury</a>, qui est un langage inspiré de <a href="https://fr.wikipedia.org/wiki/Prolog">Prolog</a> pour la partie logique, et Haskell pour la partie typage.</p>
<p>Pour ce qui est des langages concaténatifs, inspirés de <a href="https://fr.wikipedia.org/wiki/Forth_(langage)">Forth</a>, <a href="https://fr.wikipedia.org/wiki/Factor">Factor</a> semble être une approche moderne intéressante. Ceci dit, mes quelques lectures de tutos me donnent l'impression que mon cerveau ne gère pas bien l'approche concaténative de pile dès que ça devient un peu complexe (un peu la même sensation qu'avec J, mais pas aussi marquée).</p>
<p>J'ai vu passer assez souvent des articles sur le langage assez jeune mais plutôt actif <a href="https://en.wikipedia.org/wiki/Zig_(programming_language)">Zig</a>. Je me demande comment il se ressent en pratique par rapport au C voire au Rust ou C++.</p>
<div><a href="https://linuxfr.org/users/anaseto/journaux/retour-d-experience-sur-les-langages-de-programmation.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/122223/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/anaseto/journaux/retour-d-experience-sur-les-langages-de-programmation#comments">ouvrir dans le navigateur</a>
</p>
anasetohttps://linuxfr.org/nodes/122223/comments.atomtag:linuxfr.org,2005:News/386672018-10-02T18:20:37+02:002018-10-03T12:25:33+02:00OCaml 4.06 et 4.07Licence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>La version 4.07.0 du langage OCaml a été publiée le 10 juillet 2018 soit quelques mois après la sortie de la version 4.06.0, annoncée le 3 novembre 2017. OCaml est un langage fonctionnel de la famille des langages ML (dont font partie SML et F#). Il s’agit d’un langage fonctionnel multi‐paradigme fortement typé qui permet de mélanger librement les trois paradigmes : fonctionnel, impératif et objet.</p>
<p><img src="//img.linuxfr.org/img/687474703a2f2f6f63616d6c2e6f72672f6c6f676f2f436f6c6f75722f5356472f636f6c6f75722d6c6f676f2e737667/colour-logo.svg" alt="Logo OCaml" title="Source : http://ocaml.org/logo/Colour/SVG/colour-logo.svg"></p>
<p>OCaml arrive en version 4.07 avec un tout nouvel espace de noms, <code>Stdlib</code>, pour sa bibliothèque standard. Ce nouvel espace de noms présage l’intégration progressive de nouveaux modules dans la bibliothèque standard.</p>
<p>Un autre changement majeur, OCaml 4.06 marque la fin de la transition vers des chaînes de caractères immuables, changement amorcé dès <a href="//linuxfr.org/news/ocaml-4-02#cha%C3%AEnes-de-caract%C3%A8res-immutables">OCaml 4.02</a> .</p>
<p>À côté de ces changements majeurs, on retrouve de nombreuses améliorations de qualité de vie : de nouveaux opérateurs d’indexation et des champs hérités pour les types objets. Mais aussi pas mal de travail de fond pour préparer l’intégration de la branche <em>multicore</em>, améliorer les passes d’optimisations Flambda, ou faire évoluer le système de types en fixant des irrégularités.</p>
</div><ul><li>lien nᵒ 1 : <a title="https://ocaml.org/releases/4.07.0.html" hreflang="en" href="https://linuxfr.org/redirect/102553">OCaml 4.07.0</a></li><li>lien nᵒ 2 : <a title="https://ocaml.org/releases/4.06.html" hreflang="en" href="https://linuxfr.org/redirect/102554">OCaml 4.06.0</a></li><li>lien nᵒ 3 : <a title="http://caml.inria.fr/pub/docs/manual-ocaml-4.07/" hreflang="en" href="https://linuxfr.org/redirect/102785">Manuel de référence</a></li><li>lien nᵒ 4 : <a title="https://ocaml.org/" hreflang="en" href="https://linuxfr.org/redirect/102787">Site officiel</a></li><li>lien nᵒ 5 : <a title="https://discuss.ocaml.org/" hreflang="en" href="https://linuxfr.org/redirect/102788">Forum officiel</a></li><li>lien nᵒ 6 : <a title="https://linuxfr.org/news/ocaml-4-04-et-4-05" hreflang="fr" href="https://linuxfr.org/redirect/102789">Dépêche sur 4.04 et 4.05</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="#toc-biblioth%C3%A8que-standard">Bibliothèque standard</a></li>
<li>
<a href="#toc-nouveaut%C3%A9s-dans-le-langage">Nouveautés dans le langage</a><ul>
<li><a href="#toc-op%C3%A9rateurs-dindexation">Opérateurs d’indexation</a></li>
<li><a href="#toc-au-monde-des-objets">Au monde des objets</a></li>
<li><a href="#toc-meilleure-int%C3%A9gration-des-types-alg%C3%A9briques-g%C3%A9n%C3%A9ralis%C3%A9s">Meilleure intégration des types algébriques généralisés</a></li>
<li><a href="#toc-du-c%C3%B4t%C3%A9-des-modules">Du côté des modules</a></li>
</ul>
</li>
<li><a href="#toc-messages-derreur">Messages d’erreur</a></li>
<li><a href="#toc-documentation">Documentation</a></li>
</ul>
<h2 id="toc-bibliothèque-standard">Bibliothèque standard</h2>
<p>Une des nouveautés majeures d’OCaml 4.07 est la migration de la bibliothèque standard vers un espace de noms propre <code>Stdlib</code>. Cette migration a pour principal objectif de pouvoir ajouter de nouveaux modules à la bibliothèque standard sans casser les programmes tiers.</p>
<p>Désormais, les modules de la bibliothèque standard sont définis au sein du module <code>Stdlib</code>, module qui est ouvert par défaut par le compilateur. Ainsi, le module <code>List</code> est, par défaut, un raccourci pour <code>Stdlib.List</code>. Néanmoins, il est désormais possible de créer un module <code>List</code> sans craindre d’écraser le module <code>Stdlib.List</code> en aval :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="n">trois</span> <span class="o">=</span> <span class="nn">List</span><span class="p">.</span><span class="n">length</span> <span class="o">[</span><span class="mi">1</span><span class="o">;</span><span class="mi">2</span><span class="o">;</span><span class="mi">3</span><span class="o">]</span>
<span class="c">(* est désormais un raccourci pour *)</span>
<span class="k">let</span> <span class="n">trois</span> <span class="o">=</span> <span class="nn">Stdlib</span><span class="p">.</span><span class="nn">List</span><span class="p">.</span><span class="n">length</span> <span class="o">[</span><span class="mi">1</span><span class="o">;</span><span class="mi">2</span><span class="o">;</span><span class="mi">3</span><span class="o">]</span>
<span class="c">(* ce qui est permet aussi d'écrire *)</span>
<span class="k">module</span> <span class="nc">List</span> <span class="o">=</span> <span class="k">struct</span> <span class="o">...</span> <span class="k">end</span>
<span class="k">let</span> <span class="n">trois</span> <span class="o">=</span> <span class="nn">Stdlib</span><span class="p">.</span><span class="nn">List</span><span class="p">.</span><span class="n">length</span> <span class="o">[</span><span class="mi">1</span><span class="o">;</span><span class="mi">2</span><span class="o">;</span><span class="mi">3</span><span class="o">]</span></code></pre>
<p>Cette solution a d’ores et déjà permis d’ajouter deux nouveaux modules à la bibliothèque standard <code>Seq</code> et <code>Float</code>. Le nouveau module <code>Seq</code> définit un nouveau type de donnée pour des itérateurs externes, tandis que <code>Float</code> regroupe les constantes réelles et les fonctions opérant sur les <code>Float</code>. De manière similaire, la bibliothèque <code>Bigarray</code> fait désormais partie de la bibliothèque standard.</p>
<p>Le dernier changement majeur est le basculement vers des chaînes de caractères immuables (<em>immutable</em>) par défaut dans OCaml 4.06. Ce changement avait été amorcé dans <a href="//linuxfr.org/news/ocaml-4-02#cha%C3%AEnes-de-caract%C3%A8res-immutables">OCaml 4.02</a>, avec une dépréciation des fonctions manipulant le type <code>string</code> de manière mutable et une option de configuration renforçant le caractère immuable. Cette dernière option est désormais activée par défaut.</p>
<h2 id="toc-nouveautés-dans-le-langage">Nouveautés dans le langage</h2>
<h3 id="toc-opérateurs-dindexation">Opérateurs d’indexation</h3>
<p>Après une <a href="//linuxfr.org/news/ocaml-4-03#operateurs-dindexation">période d’incubation</a>, il est désormais possible de définir ses propres opérateurs d’indexation en dehors des types <code>array</code>, <code>string</code> et <code>bigarray</code>. C’est particulièrement utile pour manipuler des dictionnaires :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="nc">Dict</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">include</span> <span class="nn">Map</span><span class="p">.</span><span class="nc">Make</span><span class="o">(</span><span class="nc">String</span><span class="o">)</span> <span class="c">(* importation d'un module `Map`classique *)</span>
<span class="k">let</span> <span class="o">(.?</span><span class="bp">()</span><span class="o">)</span> <span class="n">dict</span> <span class="n">clef</span> <span class="o">=</span> <span class="n">find_opt</span> <span class="n">clef</span> <span class="n">dict</span>
<span class="k">end</span>
<span class="k">open</span> <span class="nc">Dict</span>
<span class="k">let</span> <span class="n">dict</span> <span class="o">=</span> <span class="nn">Dict</span><span class="p">.</span><span class="n">of_seq</span> <span class="o">(</span><span class="nn">List</span><span class="p">.</span><span class="n">to_seq</span> <span class="o">[</span><span class="s2">"one"</span><span class="o">,</span> <span class="mi">1</span><span class="o">;</span> <span class="s2">"dos"</span><span class="o">,</span> <span class="mi">2</span><span class="o">;</span> <span class="s2">"drei"</span><span class="o">,</span> <span class="mi">3</span><span class="o">])</span>
<span class="k">let</span> <span class="n">trois</span> <span class="o">=</span> <span class="n">dict</span><span class="o">.?(</span><span class="s2">"drei"</span><span class="o">)</span>
<span class="c">(* ou *)</span>
<span class="k">let</span> <span class="n">trois</span> <span class="o">=</span> <span class="n">dict</span><span class="o">.</span><span class="nn">Dict</span><span class="p">.</span><span class="o">?(</span><span class="s2">"drei"</span><span class="o">)</span></code></pre>
<p>Ou pour définir des formes de tableaux spécialisés sans perdre la syntaxe pratique des tableaux généralistes.</p>
<p>Pour bien marquer la différence entre ces nouveaux opérateurs d’indexation et les opérateurs d’indexation de base, leur nom doit comporter au moins un symbole supplémentaire entre le point <code>.</code> et la parenthèse ouvrante <code>(</code>.</p>
<p>Cependant, la syntaxe a encore besoin d’un peu de rodage pour être vraiment utilisable pour les tableaux multidimensionels des librairies de calcul numérique comme <a href="https://github.com/owlbarn/owl">owl</a>.</p>
<h3 id="toc-au-monde-des-objets">Au monde des objets</h3>
<p>Le système objet d’OCaml a un champ d’application moins vaste que dans les langages orientés objet comme C++ ou Java. En partie parce que le système de modules répond à un grand nombre des questions de modularité et d’encapsulations qui sont le domaine des objets dans un langage purement objet.<br>
Les objets n’en demeurent pas moins utiles, et OCaml 4.06 apporte une nouvelle option pour composer plus facilement des types objets : les champs hérités.<br>
Par exemple, on peut partir d’un type animal :</p>
<pre><code class="OCaml"><span class="k">type</span> <span class="n">animal</span> <span class="o">=</span> <span class="o"><</span> <span class="n">respire</span><span class="o">:</span> <span class="kt">unit</span> <span class="o">></span></code></pre>
<p>Ce qui définit le type d’un objet doté d’une méthode <code>respire</code> sans argument. On peut ensuite définir un type mobile :</p>
<pre><code class="OCaml"><span class="k">type</span> <span class="n">mobile</span> <span class="o">=</span> <span class="o"><</span> <span class="n">avance</span><span class="o">:</span> <span class="kt">int</span> <span class="o">></span></code></pre>
<p>Puis combiner les deux :</p>
<pre><code class="OCaml"><span class="k">type</span> <span class="n">animal_mobile</span> <span class="o">=</span> <span class="o"><</span> <span class="n">animal</span><span class="o">;</span> <span class="n">mobile</span> <span class="o">></span></code></pre>
<p>Il était déjà possible d’arriver à ce résultat en jonglant avec les types de classes, mais cette nouvelle méthode est bien plus intuitive.</p>
<p>Ce genre de code met en exergue une des particularités du système objet d’OCaml, qui est structurel : un objet n’est défini que par les méthodes qu’on peut lui envoyer et non par sa classe, ce qui donne au final un système qui s’apparente à une version statique du <em>duck‐typing</em> à la Python.</p>
<h3 id="toc-meilleure-intégration-des-types-algébriques-généralisés">Meilleure intégration des types algébriques généralisés</h3>
<p>Un des travaux de fond dans OCaml 4.07 a été l’amélioration du traitement des types algébriques généralisés (ou GADT) au sein du vérificateur de types.</p>
<p>Lors de l’introduction des GADT dans OCaml 4.00, ceux‐ci se sont souvent vus octroyés des chemins d’exécution particuliers pour séparer cette nouvelle extension du cœur mieux testé du langage. Après sept versions, les codes côté GADT et côté classique ont été unifiés. D’un point de vue utilisateur, cela signifie surtout qu’il n’est plus nécessaire de qualifier les GADT lorsque l’on filtre un schéma avec <code>match</code> :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="nc">M</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">type</span> <span class="n">en_attente</span> <span class="o">=</span>
<span class="o">|</span> <span class="nc">Fini</span> <span class="o">:</span> <span class="n">en_attente</span>
<span class="o">|</span> <span class="nc">En_cours</span> <span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="o">*</span> <span class="o">(</span><span class="k">'</span><span class="n">a</span> <span class="o">-></span> <span class="n">en_attente</span><span class="o">)</span> <span class="o">-></span> <span class="n">en_attente</span>
<span class="k">end</span>
<span class="k">let</span> <span class="n">execute</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="nn">M</span><span class="p">.</span><span class="n">en_attente</span><span class="o">)</span> <span class="o">=</span> <span class="k">match</span> <span class="n">x</span> <span class="k">with</span>
<span class="o">|</span> <span class="nc">Fini</span> <span class="o">-></span> <span class="nn">M</span><span class="p">.</span><span class="nc">Fini</span>
<span class="o">|</span> <span class="nc">En_cours</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span><span class="n">f</span><span class="o">)</span> <span class="o">-></span> <span class="n">f</span> <span class="n">x</span></code></pre>
<p>Alors qu’il fallait précédemment qualifier les branches du <em>match</em> :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="n">execute</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="nn">M</span><span class="p">.</span><span class="n">en_attente</span><span class="o">)</span> <span class="o">=</span> <span class="k">match</span> <span class="n">x</span> <span class="k">with</span>
<span class="o">|</span> <span class="nn">M</span><span class="p">.</span><span class="nc">Fini</span> <span class="o">-></span> <span class="nn">M</span><span class="p">.</span><span class="nc">Fini</span>
<span class="o">|</span> <span class="nn">M</span><span class="p">.</span><span class="nc">En_cours</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span><span class="n">f</span><span class="o">)</span> <span class="o">-></span> <span class="n">f</span> <span class="n">x</span></code></pre>
<p>Une des nouveautés, qui concerne plus les usages avancés, est l’apparition de variants vides, c’est‐à‐dire de types de variants sans aucune valeur associée :</p>
<pre><code class="OCaml"><span class="k">type</span> <span class="n">unique</span> <span class="o">=</span> <span class="o">|</span></code></pre>
<p>Ce type étrange est principalement utile pour créer de manière explicite un nouveau type unique, qui ne sera utilisé que dans le système de type ou dans la génération de code.</p>
<h3 id="toc-du-côté-des-modules">Du côté des modules</h3>
<p>Pour les utilisateurs avancés, il est désormais plus facile de préserver les alias de modules, que ce soit avec <code>module type of</code> ou des contraintes <code>with modules</code>.<br>
Par exemple, avec :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="nc">A</span> <span class="o">=</span> <span class="k">struct</span> <span class="k">type</span> <span class="n">t</span> <span class="k">end</span>
<span class="k">module</span> <span class="nc">B</span> <span class="o">=</span> <span class="k">struct</span> <span class="k">module</span> <span class="nc">Alias</span> <span class="o">=</span> <span class="nc">A</span> <span class="k">end</span>
<span class="k">module</span> <span class="k">type</span> <span class="nc">S</span> <span class="o">=</span> <span class="k">module</span> <span class="k">type</span> <span class="k">of</span> <span class="nc">B</span></code></pre>
<p><code>S</code> est désormais équivalent à :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="k">type</span> <span class="nc">S'</span> <span class="o">=</span> <span class="k">sig</span> <span class="k">module</span> <span class="nc">Alias</span> <span class="o">=</span> <span class="nc">A</span> <span class="k">end</span></code></pre>
<p>plutôt que :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="k">type</span> <span class="nc">S_sans_alias</span> <span class="o">=</span> <span class="k">sig</span>
<span class="k">module</span> <span class="nc">Alias</span><span class="o">:</span> <span class="k">sig</span> <span class="k">type</span> <span class="n">t</span> <span class="k">end</span>
<span class="k">end</span></code></pre>
<p>L’ancien comportement peut être rétabli en ajoutant un attribut <code>[@remove_aliases]</code> :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="k">type</span> <span class="nc">S_sans_alias</span> <span class="o">=</span> <span class="k">module</span> <span class="k">type</span> <span class="k">of</span> <span class="nc">S</span> <span class="o">[@</span><span class="n">remove_aliases</span><span class="o">]</span></code></pre>
<p>Un autre changement est qu’il est désormais possible d’utiliser des substitutions destructives à l’intérieur de sous‐modules :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="k">type</span> <span class="nc">S</span> <span class="o">=</span> <span class="k">sig</span>
<span class="k">module</span> <span class="nc">Inner</span><span class="o">:</span> <span class="k">sig</span>
<span class="k">type</span> <span class="n">t</span>
<span class="k">val</span> <span class="n">x</span><span class="o">:</span> <span class="n">t</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">module</span> <span class="k">type</span> <span class="nc">S'</span> <span class="o">=</span> <span class="nc">S</span> <span class="k">with</span> <span class="k">type</span> <span class="nn">Inner</span><span class="p">.</span><span class="n">t</span> <span class="o">:=</span> <span class="kt">int</span></code></pre>
<h2 id="toc-messages-derreur">Messages d’erreur</h2>
<p>Les messages d’erreur émis par OCaml ne sont pas toujours très clairs. Des efforts sont en cours pour corriger ce point. Par exemple, OCaml 4.07 essaie d’expliquer plus en détails certaines erreurs courantes chez les débutants, par exemple en cas d’oubli d’un argument <code>()</code> :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="n">un</span> <span class="bp">()</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">let</span> <span class="n">test</span> <span class="o">=</span> <span class="o">(</span><span class="mi">0</span> <span class="o">=</span> <span class="n">un</span><span class="o">);;</span></code></pre>
<blockquote>
<p>Error: This expression has type unit -> int<br>
but an expression was expected of type int<br>
Hint: Did you forget to provide `()' as argument?</p>
</blockquote>
<p>Le contexte de certaines erreurs est désormais mieux détaillé :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="bp">()</span> <span class="o">=</span> <span class="k">if</span> <span class="bp">()</span> <span class="k">then</span> <span class="bp">()</span></code></pre>
<blockquote>
<p>Error: This variant expression is expected to have type bool<br>
because it is in the condition of an if-statement</p>
</blockquote>
<p>plutôt que juste :</p>
<blockquote>
<p>Error: This variant expression is expected to have type bool</p>
</blockquote>
<p>Les types faiblement polymorphiques, qui auparavant étaient marqués par juste un tiret <code>_</code>, ont maintenant des noms plus explicites :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="n">none</span> <span class="o">=</span> <span class="n">ref</span> <span class="nc">None</span></code></pre>
<blockquote>
<p>none: '_weak1 option ref</p>
</blockquote>
<p>Cela dans l’espoir de les rendre plus apparents et facilement cherchables, notamment dans le <a href="http://caml.inria.fr/pub/docs/manual-ocaml/polymorphism.html#sec53">manuel</a>.</p>
<p>Enfin, pour les utilisateurs plus avancés, les messages d’erreurs concernant les foncteurs et modules sont passés de :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="nc">F</span><span class="bp">()</span> <span class="o">=</span> <span class="k">struct</span> <span class="k">end</span>
<span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="nn">F</span><span class="p">.</span><span class="n">x</span></code></pre>
<blockquote>
<p>Error: The module F is a functor, not a structure</p>
</blockquote>
<p>à une version qui explique pourquoi l’extrait de code plus haut est invalide :</p>
<blockquote>
<p>Error: The module F is a functor, it cannot have any components</p>
</blockquote>
<h2 id="toc-documentation">Documentation</h2>
<p>Le <a href="http://caml.inria.fr/pub/docs/manual-ocaml-4.07/">manuel de référence</a> a fait peau neuve pour la version 4.07. L’apparence graphique du manuel commençait à faire un peu daté, et un rafraîchissement de façade était de rigueur.</p>
<p>Sur le fond, le manuel s’est enrichi d’un <a href="http://caml.inria.fr/pub/docs/manual-ocaml/polymorphism.html">nouveau chapitre</a> sur les troubles liés au polymorphisme, que ce soit les types faiblement polymorphiques :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="n">nouvel_identite</span> <span class="bp">()</span> <span class="o">=</span> <span class="k">fun</span> <span class="n">x</span> <span class="o">-></span> <span class="n">x</span>
<span class="k">let</span> <span class="n">id</span> <span class="o">=</span> <span class="n">nouvel_identite</span> <span class="bp">()</span>
<span class="k">let</span> <span class="n">erreur</span> <span class="o">=</span> <span class="n">id</span> <span class="n">id</span></code></pre>
<p>Le polymorphisme d’ordre supérieur :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="n">f</span> <span class="n">identite</span> <span class="o">=</span> <span class="n">identite</span> <span class="mi">1</span><span class="o">,</span> <span class="n">identite</span> <span class="mi">2</span><span class="o">.</span></code></pre>
<p>ou les fonctions polymorphiquement récursives :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="k">rec</span> <span class="n">etrange</span> <span class="n">l</span> <span class="o">=</span> <span class="k">match</span> <span class="n">l</span> <span class="k">with</span>
<span class="o">|</span> <span class="bp">[]</span> <span class="o">-></span> <span class="mi">0</span>
<span class="o">|</span> <span class="o">[</span> <span class="o">_</span> <span class="o">]</span> <span class="o">-></span> <span class="mi">1</span>
<span class="o">|</span> <span class="n">a</span> <span class="o">::</span> <span class="n">q</span> <span class="o">-></span> <span class="n">etrange</span> <span class="o">[</span><span class="n">q</span><span class="o">];;</span></code></pre>
</div><div><a href="https://linuxfr.org/news/ocaml-4-06-et-4-07.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/114730/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/ocaml-4-06-et-4-07#comments">ouvrir dans le navigateur</a>
</p>
octachronZeroHeureSnarkJulien JorgeDavy DefaudPierre JarillonNils Ratusznikj_mhttps://linuxfr.org/nodes/114730/comments.atomtag:linuxfr.org,2005:Diary/378002018-03-10T02:23:30+01:002018-03-10T02:23:30+01:00Portage de TapTempo en OCamlLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<p>Je me désespérais de voir apparaître le portage de TapTempo en OCaml alors je m'y colle.<br><a href="https://github.com/gndl/taptempocaml">Taptempocaml</a> est donc le portage du désormais célèbre TapTempo en <a href="http://ocaml.org/">OCaml</a>.<br>
Ce portage n’a pas la prétention de présenter l’état de l’art de la programmation fonctionnelle. Le but ici est plutôt de fournir le code le plus simple et le plus proche de l’original et ceci pour trois raisons :<br>
I. Bien que le langage fournisse des fonctionnalités très évoluées, dans 93 % des cas, ce dont on a réellement besoin c’est d’une solution simple et directe.<br>
II. La proximité de ce portage avec l’original facilitera aux éventuels lecteurs la comparaison avec celui-ci.<br>
III. Je suis fainéant.</p>
<p>En principe, ce portage est ISO-fonctionnel avec l’original.<br>
Je ne présente ici que la fonction principale :</p>
<pre><code class="ocaml"><span class="k">open</span> <span class="nn">I18n</span><span class="p">.</span><span class="nc">Gettext</span>
<span class="k">let</span> <span class="n">run</span> <span class="n">sampleSize</span> <span class="n">resetTime</span> <span class="n">precision</span> <span class="o">=</span>
<span class="k">let</span> <span class="n">hitTimePoints</span> <span class="o">=</span> <span class="nn">Queue</span><span class="p">.</span><span class="n">create</span><span class="bp">()</span> <span class="k">in</span>
<span class="n">print_string</span><span class="o">(</span><span class="n">s_</span><span class="s2">"Hit enter key for each beat (q to quit).</span><span class="se">\n</span><span class="s2">"</span><span class="o">);</span>
<span class="k">while</span> <span class="n">input_char</span> <span class="n">stdin</span> <span class="o"><></span> <span class="sc">'q'</span> <span class="k">do</span>
<span class="k">let</span> <span class="n">currentTime</span> <span class="o">=</span> <span class="nn">Unix</span><span class="p">.</span><span class="n">gettimeofday</span><span class="bp">()</span> <span class="k">in</span>
<span class="k">if</span> <span class="nn">Queue</span><span class="p">.</span><span class="n">is_empty</span> <span class="n">hitTimePoints</span>
<span class="o">||</span> <span class="n">currentTime</span> <span class="o">-.</span> <span class="nn">Queue</span><span class="p">.</span><span class="n">top</span> <span class="n">hitTimePoints</span> <span class="o">></span> <span class="n">resetTime</span>
<span class="k">then</span> <span class="o">(</span>
<span class="nn">Queue</span><span class="p">.</span><span class="n">clear</span> <span class="n">hitTimePoints</span><span class="o">;</span> <span class="c">(* Reset if the hit diff is too big. *)</span>
<span class="n">print_string</span><span class="o">(</span><span class="n">s_</span><span class="s2">"[Hit enter key one more time to start bpm computation...]</span><span class="se">\n</span><span class="s2">"</span><span class="o">)</span>
<span class="o">)</span>
<span class="k">else</span> <span class="o">(</span>
<span class="k">let</span> <span class="n">occurenceCount</span> <span class="o">=</span> <span class="nn">Queue</span><span class="p">.</span><span class="n">length</span> <span class="n">hitTimePoints</span> <span class="k">in</span>
<span class="c">(* Remove the older time from hitTimePoints with Queue.pop if the sample size is reached.</span>
<span class="c"> Otherwise it is kept in the queue with Queue.top. *)</span>
<span class="k">let</span> <span class="n">olderTime</span> <span class="o">=</span> <span class="nn">Queue</span><span class="p">.</span><span class="o">(</span><span class="k">if</span> <span class="n">occurenceCount</span> <span class="o"><</span> <span class="n">sampleSize</span> <span class="k">then</span> <span class="n">top</span> <span class="k">else</span> <span class="n">pop</span><span class="o">)</span> <span class="n">hitTimePoints</span> <span class="k">in</span>
<span class="k">let</span> <span class="n">bpm</span> <span class="o">=</span> <span class="mi">60</span><span class="o">.</span> <span class="o">*.</span> <span class="n">float_of_int</span> <span class="n">occurenceCount</span> <span class="o">/.</span> <span class="o">(</span><span class="n">currentTime</span> <span class="o">-.</span> <span class="n">olderTime</span><span class="o">)</span> <span class="k">in</span>
<span class="nn">Printf</span><span class="p">.</span><span class="n">printf</span><span class="o">(</span><span class="n">f_</span><span class="s2">"Tempo: %.*f bpm%!"</span><span class="o">)</span> <span class="n">precision</span> <span class="n">bpm</span><span class="o">;</span>
<span class="o">);</span>
<span class="nn">Queue</span><span class="p">.</span><span class="n">add</span> <span class="n">currentTime</span> <span class="n">hitTimePoints</span><span class="o">;</span>
<span class="k">done</span><span class="o">;</span>
<span class="n">print_string</span><span class="o">(</span><span class="n">s_</span><span class="s2">"Bye Bye!</span><span class="se">\n</span><span class="s2">"</span><span class="o">)</span>
<span class="k">let</span> <span class="bp">()</span> <span class="o">=</span>
<span class="k">let</span> <span class="n">sampleSize</span><span class="o">,</span> <span class="n">resetTime</span><span class="o">,</span> <span class="n">precision</span> <span class="o">=</span> <span class="nn">Options</span><span class="p">.</span><span class="n">createFromArgs</span> <span class="nn">Sys</span><span class="p">.</span><span class="n">argv</span>
<span class="k">in</span>
<span class="n">run</span> <span class="n">sampleSize</span> <span class="n">resetTime</span> <span class="n">precision</span></code></pre>
<p>Si la motivation première de ce portage est la joie de participer à l’enthousiasme frénétique qui entoure cette vague de portage de TapTempo, cet exercice m’aura en outre permit de découvrir la bibliothèque Gettext et le module Arg. Rien que pour cela je remercie <a href="//linuxfr.org/users/mzf">mfz</a> ainsi que tout les auteurs des différents portages de TapTempo.</p>
<p>Maintenant, ce qui serait vraiment intéressant, ce serait le portage de TapTempo en <a href="https://reasonml.github.io/">Reason</a>…</p><div><a href="https://linuxfr.org/users/duga/journaux/portage-de-taptempo-en-ocaml.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/113915/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/duga/journaux/portage-de-taptempo-en-ocaml#comments">ouvrir dans le navigateur</a>
</p>
gndlhttps://linuxfr.org/nodes/113915/comments.atomtag:linuxfr.org,2005:News/376422017-07-16T08:26:38+02:002017-07-17T11:45:07+02:00OCaml 4.04 et 4.05Licence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>La version 4.05.0 du langage OCaml vient d’être publiée, le 13 juillet 2017 ; quelque mois après la sortie de la version 4.04.0, annoncée le 4 novembre 2016. OCaml est un langage fonctionnel de la famille des langages ML (dont font partie <a href="https://en.wikipedia.org/wiki/Standard_ML">SML</a> et <a href="https://fr.wikipedia.org/wiki/F_sharp">F#</a>). Il s’agit d’un langage fonctionnel multi‐paradigme fortement typé qui permet de mélanger librement les paradigmes fonctionnel, impératif et objet.</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6f63616d6c2e6f72672f696d672f636f6c6f75722d6c6f676f2d77686974652e737667/colour-logo-white.svg" alt="LOGO" title="Source : https://ocaml.org/img/colour-logo-white.svg"></p>
<p>Il s’agit des deux premières versions après le passage à un cycle court de développement (6 mois). Elles contiennent assez peu de changements majeurs et peuvent être considérées comme des versions de maturation, en particulier pour la nouvelle phase d’optimisation Flambda introduite dans la version 4.03.</p>
<p>On note cependant l’intégration de deux nouveaux outils dans le compilateur : un profileur de mémoire et un <em>fuzzer</em> ; mais aussi quelques améliorations du langage et de la bibliothèque standard. Pas mal de changements ont aussi eu lieu dans les entrailles du compilateur et n’ont pas encore débouché sur des changements visibles à la surface du langage.</p>
<p>Une des nouveautés les plus surprenantes de ces cycles de développement est probablement l’apparition d’une nouvelle syntaxe alternative à OCaml, nommé Reason(ml), sous l’impulsion d’une équipe de Facebook.</p></div><ul><li>lien nᵒ 1 : <a title="http://ocaml.org/" hreflang="fr" href="https://linuxfr.org/redirect/100032">Site officiel</a></li><li>lien nᵒ 2 : <a title="https://discuss.ocaml.org/" hreflang="en" href="https://linuxfr.org/redirect/100033">Discours officiel</a></li><li>lien nᵒ 3 : <a title="https://caml.inria.fr/pub/docs/manual-ocaml/spacetime.html" hreflang="en" href="https://linuxfr.org/redirect/100063">Manuel OCaml : spacetime, profileur de mémoire</a></li><li>lien nᵒ 4 : <a title="http://caml.inria.fr/pub/docs/manual-ocaml/afl-fuzz.html" hreflang="en" href="https://linuxfr.org/redirect/100064">Manuel OCaml : afl-fuzz</a></li><li>lien nᵒ 5 : <a title="https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec258" hreflang="en" href="https://linuxfr.org/redirect/100065">Manual OCaml : exceptions locales</a></li><li>lien nᵒ 6 : <a title="https://facebook.github.io/reason/" hreflang="en" href="https://linuxfr.org/redirect/100122">Reason</a></li><li>lien nᵒ 7 : <a title="https://sympa.inria.fr/sympa/arc/caml-list/2017-07/msg00058.html" hreflang="en" href="https://linuxfr.org/redirect/100278">Annonce officielle de la 4.05</a></li><li>lien nᵒ 8 : <a title="https://sympa.inria.fr/sympa/arc/caml-list/2016-11/msg00010.html" hreflang="en" href="https://linuxfr.org/redirect/100279">Annonce officielle de la 4.04</a></li><li>lien nᵒ 9 : <a title="https://linuxfr.org/news/ocaml-4-03" hreflang="fr" href="https://linuxfr.org/redirect/100280">Dépêche LinuxFr.org sur OCaml 4.03</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#outils-de-d%C3%A9veloppement">Outils de développement</a><ul>
<li><a href="#spacetime-profileur-de-m%C3%A9moire">Spacetime: profileur de mémoire</a></li>
<li><a href="#int%C3%A9gration-de-afl-fuzzer">Intégration de afl-fuzzer</a></li>
</ul>
</li>
<li>
<a href="#%C3%89volution-du-langage-ocaml">Évolution du langage OCaml</a><ul>
<li><a href="#exceptions-locales">Exceptions locales</a></li>
<li><a href="#ouverture-locale-de-module-dans-les-motifs">Ouverture locale de module dans les motifs</a></li>
<li><a href="#repr%C3%A9sentation-en-m%C3%A9moire-optimis%C3%A9e">Représentation en mémoire optimisée</a></li>
<li><a href="#vers-des-cha%C3%AEnes-de-caract%C3%A8res-immuables">Vers des chaînes de caractères immuables</a></li>
<li><a href="#%C3%89volution-de-la-biblioth%C3%A8que-standard">Évolution de la bibliothèque standard</a></li>
</ul>
</li>
<li><a href="#am%C3%A9lioration-du-compilateur">Amélioration du compilateur</a></li>
<li>
<a href="#reason">Reason</a><ul>
<li><a href="#lobjectif">L’objectif</a></li>
<li><a href="#ce-quest-reason">Ce qu’est Reason</a></li>
<li><a href="#un-avenir-impr%C3%A9visible">Un avenir imprévisible</a></li>
</ul>
</li>
</ul><h2 id="outils-de-développement">Outils de développement</h2>
<p>Du côté des outils de développement, deux nouveaux outils ont été intégrés à la distribution OCaml: un profileur de mémoire, Spacetime, et un fuzzer, afl-fuzzer.</p>
<h3 id="spacetime-profileur-de-mémoire">Spacetime: profileur de mémoire</h3>
<p>Le nouveau profileur de mémoire baptisé spacetime n’est pas activé par défaut à cause de son impact sur la performance et la mémoire des processus profilés. Il est cependant aisément disponible à travers un <em>switch</em> opam, le gestionnaire de paquets d’OCaml qui gère aussi les versions installées du compilateur Ocaml. Installer un compilateur OCaml avec le prise en charge de spacetime activée se fait avec une simple ligne :</p>
<pre><code class="bash">$ opam switch <span class="m">4</span>.05.0+spacetime</code></pre>
<p>Une fois spacetime activé, n’importe quel programme peut être profilé en définissant la variable d’environnement <code>OCAML_SPACETIME_INTERVAL</code>. On peut, par exemple, s’intéresser à la consommation mémoire lors de l’analyse des dépendances du compilateur :</p>
<pre><code class="bash">$ <span class="nv">OCAML_SPACETIME_INTERVAL</span><span class="o">=</span><span class="m">50</span> codept ocaml-compiler</code></pre>
<p>Les traces sont ensuite sauvegardées sous la forme <code>spacetime-$process-id</code> et peuvent être analysées grâce à l’outil <code>perf_spacetime</code> qui dispose d’un mode terminal et d’un mode service Web permettant d’explorer en détails la consommation mémoire.<br><img src="//img.linuxfr.org/img/687474703a2f2f7069782e746f696c652d6c696272652e6f72672f75706c6f61642f6f726967696e616c2f313439333731383431332e706e67/1493718413.png" alt="Mémoire consommée" title="Source : http://pix.toile-libre.org/upload/original/1493718413.png"></p>
<p>Dans le cas illustré, on peut voir que la consommation de la mémoire se structure en cycles composés d’une phase d’exploration durant laquelle la consommation de la mémoire croît, suivie d’une phase de résolution qui permet au ramasse‐miettes de collecter la majorité de la mémoire utilisée dans la phase précédente.</p>
<h3 id="intégration-de-afl-fuzzer">Intégration de afl-fuzzer</h3>
<p><em>American fuzzy lop</em> (aussi connu sous le nom de afl-fuzzer) est un fuzzer, c’est‐à‐dire un outil pour tester des logiciels en leur injectant des données aléatoires en entrée.</p>
<p>Contrairement à la plupart des <em>fuzzers</em>, <em>afl-fuzzers</em> va plus loin que la simple injection de données aléatoires non corrélées : il observe le comportement interne du programme testé pour essayer de forger des données d’entrée qui vont explorer de nouvelles branches du code à éprouver. Cela permet d’améliorer le taux de couverture du test, au prix d’une nécessaire instrumentation du code. La mouture 4.05 d’OCaml permet désormais d’ajouter cette instrumentation au code compilé grâce à une simple option de compilation.</p>
<p>Comme exemple basique d’utilisation, on peut considérer ce code qui échoue sur un cas très particulier :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="bp">()</span> <span class="o">=</span>
<span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="n">read_line</span> <span class="bp">()</span> <span class="k">in</span>
<span class="k">if</span> <span class="nn">String</span><span class="p">.</span><span class="n">length</span> <span class="n">s</span> <span class="o">></span> <span class="mi">5</span> <span class="k">then</span>
<span class="k">match</span> <span class="n">s</span><span class="o">.[</span><span class="mi">0</span><span class="o">],</span> <span class="n">s</span><span class="o">.[</span><span class="mi">1</span><span class="o">],</span> <span class="n">s</span><span class="o">.[</span><span class="mi">2</span><span class="o">],</span> <span class="n">s</span><span class="o">.[</span><span class="mi">3</span><span class="o">],</span> <span class="n">s</span><span class="o">.[</span><span class="mi">4</span><span class="o">]</span> <span class="k">with</span>
<span class="o">|</span> <span class="sc">'e'</span><span class="o">,</span> <span class="sc">'c'</span> <span class="o">,</span> <span class="sc">'h'</span><span class="o">,</span> <span class="sc">'e'</span><span class="o">,</span> <span class="sc">'c'</span> <span class="o">-></span> <span class="n">failwith</span> <span class="s2">"Échec improbable"</span>
<span class="o">|</span> <span class="o">_</span> <span class="o">-></span> <span class="bp">()</span></code></pre>
<p>Pour analyser ce code avec <em>afl fuzzer</em>, il suffit d’utiliser la nouvelle option <code>-afl-instrument</code> d’<em>ocamlopt</em>, fournir quelques cas de base, puis de lancer <em>afl-fuzz</em> lui‐même, qui va utiliser un algorithme générique sur ces cas de base pour générer de nouveaux cas à tester :</p>
<pre><code>ocamlopt -afl-instrument test.ml
afl-fuzz -i input -o output ./test.ml
</code></pre>
<p>Ce dernier trouve rapidement que, par exemple, <code>echec#Ε$5<ȹpu|Ϧģ</code> fait planter le programme. Cependant, il n’est pas assuré de trouver une entrée minimale (ici « echec ») faisant échouer le programme.</p>
<h2 id="Évolution-du-langage-ocaml">Évolution du langage OCaml</h2>
<h3 id="exceptions-locales">Exceptions locales</h3>
<p>Parmi les particularités d’OCaml, il y a ces exceptions qui sont suffisamment rapides pour être utilisées en tant que structures de contrôle. OCaml 4.04 introduit une notation simplifiée pour les exceptions locales :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="n">recherche_premier</span> <span class="o">(</span><span class="k">type</span> <span class="n">a</span><span class="o">)</span> <span class="n">predicat</span> <span class="n">table</span><span class="o">=</span>
<span class="k">let</span> <span class="k">exception</span> <span class="nc">Trouve</span> <span class="k">of</span> <span class="n">a</span> <span class="k">in</span>
<span class="k">try</span>
<span class="nn">Array</span><span class="p">.</span><span class="n">iter</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="o">-></span> <span class="k">if</span> <span class="n">predicat</span> <span class="n">x</span> <span class="k">then</span> <span class="k">raise</span> <span class="o">(</span><span class="nc">Trouve</span> <span class="n">x</span><span class="o">)</span> <span class="o">)</span> <span class="n">table</span><span class="o">;</span>
<span class="nc">None</span>
<span class="k">with</span>
<span class="nc">Trouve</span> <span class="n">x</span> <span class="o">-></span> <span class="nc">Some</span> <span class="n">x</span></code></pre>
<p>Avant l’introduction de cette nouvelle notation, il fallait passer par un module local pour définir l’exception :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="n">recherche_premier</span> <span class="o">(</span><span class="k">type</span> <span class="n">a</span><span class="o">)</span> <span class="n">predicat</span> <span class="n">table</span><span class="o">=</span>
<span class="k">let</span> <span class="k">module</span> <span class="nc">M</span> <span class="o">=</span> <span class="k">struct</span> <span class="k">exception</span> <span class="nc">Trouve</span> <span class="k">of</span> <span class="n">a</span> <span class="k">end</span> <span class="k">in</span>
<span class="k">try</span>
<span class="nn">Array</span><span class="p">.</span><span class="n">iter</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="o">-></span> <span class="k">if</span> <span class="n">predicat</span> <span class="n">x</span> <span class="k">then</span> <span class="k">raise</span> <span class="o">(</span><span class="nn">M</span><span class="p">.</span><span class="nc">Trouve</span> <span class="n">x</span><span class="o">)</span> <span class="o">)</span> <span class="n">table</span><span class="o">;</span>
<span class="nc">None</span>
<span class="k">with</span>
<span class="nn">M</span><span class="p">.</span><span class="nc">Trouve</span> <span class="n">x</span> <span class="o">-></span> <span class="nc">Some</span> <span class="n">x</span></code></pre>
<p>De plus, dans le futur, ces exceptions locales pourraient faire l’objet d’optimisations spécifiques.</p>
<h3 id="ouverture-locale-de-module-dans-les-motifs">Ouverture locale de module dans les motifs</h3>
<p>Une des nouveautés d’OCaml 4.04 est la possibilité d’ouvrir localement un module à l’intérieur d’un motif :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="nc">M</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">type</span> <span class="n">t</span> <span class="o">=</span> <span class="nc">A</span> <span class="o">|</span> <span class="nc">B</span> <span class="o">|</span> <span class="nc">C</span>
<span class="k">type</span> <span class="n">u</span> <span class="o">=</span> <span class="nc">List</span> <span class="k">of</span> <span class="n">t</span> <span class="kt">list</span> <span class="o">|</span> <span class="nc">Array</span> <span class="k">of</span> <span class="n">t</span> <span class="kt">array</span>
<span class="k">end</span>
<span class="k">let</span> <span class="n">est_ce_la_liste_ABC</span> <span class="n">x</span> <span class="o">=</span> <span class="k">match</span> <span class="n">x</span> <span class="k">with</span>
<span class="o">|</span> <span class="nn">M</span><span class="p">.</span><span class="o">(</span> <span class="nc">List</span> <span class="o">[</span><span class="nc">A</span><span class="o">;</span><span class="nc">B</span><span class="o">;</span><span class="nc">C</span><span class="o">]</span> <span class="o">)</span> <span class="o">-></span> <span class="bp">true</span>
<span class="o">|</span> <span class="o">_</span> <span class="o">-></span> <span class="bp">false</span></code></pre>
<p>Comme dans le cas des expressions, ouvrir localement un module permet d’importer les types et valeurs dans la portée (<em>scope</em>) courante sans polluer la portée en dehors du motif. Cette construction permet également de rétablir une certaine symétrie entre motifs et expressions, comme dans l’exemple suivant uniquement valide depuis OCaml 4.04 :</p>
<pre><code class="OCaml"><span class="k">module</span> <span class="nc">N</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">type</span> <span class="n">r</span> <span class="o">=</span> <span class="o">{</span> <span class="n">x</span> <span class="o">:</span> <span class="kt">int</span> <span class="o">}</span>
<span class="k">end</span>
<span class="k">let</span> <span class="nn">N</span><span class="p">.</span><span class="o">{</span> <span class="n">x</span> <span class="o">}</span> <span class="c">(* { x } est un motif ici *)</span> <span class="o">=</span>
<span class="nn">N</span><span class="p">.</span><span class="o">{</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">}</span> <span class="c">(* { x = 1} est une expression de ce côté-ci *)</span></code></pre>
<h3 id="représentation-en-mémoire-optimisée">Représentation en mémoire optimisée</h3>
<p>Il est désormais possible d’optimiser la représentation en mémoire des variants avec un seul constructeur et un seul argument ou des enregistrements avec un seul champ en les annotant avec <code>[@@unboxed]</code> :</p>
<pre><code class="OCaml"><span class="k">type</span> <span class="k">'</span><span class="n">a</span> <span class="n">s</span> <span class="o">=</span> <span class="nc">A</span> <span class="k">of</span> <span class="k">'</span><span class="n">a</span> <span class="o">[@@</span><span class="n">unboxed</span><span class="o">]</span>
<span class="k">type</span> <span class="k">'</span><span class="n">a</span> <span class="n">r</span> <span class="o">=</span> <span class="o">{</span> <span class="n">f</span><span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="o">}</span> <span class="o">[@@</span><span class="n">unboxed</span><span class="o">]</span></code></pre>
<p>Sans l’annotation <code>[@@unboxed]</code>, ces deux types seraient représentés en mémoire sous la forme d’un bloc OCaml composé d’un en‐tête et d’un champ :</p>
<pre><code>┌────────┬───────────┐
│ entête │ champs[0] │
└────────┴───────────┘
</code></pre>
<p>Pour des types plus complexes, l’en‐tête contient des informations sur le nombre de champs dans le bloc et sur l’étiquette du constructeur. Cependant, pour ces cas particuliers, l’en‐tête n’apporte aucune information et il est possible de l’élider.</p>
<p>Cette optimisation est particulièrement utile dans le cadre des types algébriques généralisés, puisqu’elle permet d’introduire des types existentiels sans payer de coût en mémoire. Par exemple, si l’on souhaite oublier le type des éléments d’une liste, on peut introduire le type algébrique généralisé suivant :</p>
<pre><code class="OCaml"><span class="k">type</span> <span class="n">liste</span> <span class="o">=</span> <span class="nc">Any</span><span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="kt">list</span> <span class="o">-></span> <span class="n">liste</span> <span class="o">[@@</span><span class="n">unboxed</span><span class="o">]</span></code></pre>
<p>Grâce à l’annotation <code>[@@unboxed]</code>, le type <code>liste</code> aura exactement la même représentation en mémoire qu’une liste classique, et représente une version du type <code>'a list</code> qui interdit toute manipulation dépendante du type <code>'a</code> des éléments de la liste.</p>
<p>Dans la plupart des cas, cette optimisation est transparente à l’usage. Cependant, les bibliothèques de liaison (<em>bindings</em>) C‐OCaml doivent faire attention à ce changement de représentation en mémoire. Afin d’éviter de briser les bibliothèques de liaison existantes, cette optimisation n’est pas activée par défault, mais doit l’être au cas par cas avec l’annotation<code>[@@unboxed]</code> ou via l’option de compilation <code>-unboxed-types</code>.</p>
<h3 id="vers-des-chaînes-de-caractères-immuables">Vers des chaînes de caractères immuables</h3>
<p>La migration vers des chaînes de caractères immuables, initiée dans OCaml 4.02, se poursuit avec l’apparition d’une option de configuration du compilateur permettant d’en faire le comportement par défaut. Cette option n’est pas encore activée par défaut dans 4.05, mais des discussions sont en cours pour l’activer dans la prochaine version (4.06). </p>
<h3 id="Évolution-de-la-bibliothèque-standard">Évolution de la bibliothèque standard</h3>
<p>La bibliothèque standard continue d’évoluer doucement, soit pour pallier des incohérences, avec par exemple l’introduction d’une fonction <code>map</code> pour les ensembles <code>Set</code>, soit pour s’adapter à l’évolution du code idiomatique OCaml, avec par exemple l’ajout de variantes de fonctions utilisant des options plutôt que des exceptions pour gérer les éléments manquants dans des <code>Set</code> ou des <code>Map</code>.</p>
<h2 id="amélioration-du-compilateur">Amélioration du compilateur</h2>
<p>Ces deux cycles de développements auront vu aussi un grand nombre d’améliorations internes du compilateur et de son écosystème : le système de construction du compilateur est en train de subir un sévère ménage de printemps, tandis que les tests d’intégration continue ont été améliorés, notamment pour mieux supporter les anciennes versions de Windows. Parallèlement, un travail de fond est en cours pour améliorer le déverminage de programme OCaml et préparer le changement de modèle de mémoire nécessaire pour une future version multicœur d’OCaml.</p>
<p>Ces évolutions n’apportent pas encore de changements visibles pour la plupart des utilisateurs, mais devraient porter leurs fruits dans les versions à venir.</p>
<p>Un changement plus visible, même s’il ne concerne essentiellement que des utilisateurs experts, est l’intégration progressive d’une architecture de greffons (<em>plugins</em>) dans le compilateur. Pour l’instant, ces greffons peuvent, par exemple, transformer l’arbre de syntaxe abstrait comme le ferait un préprocesseur basé sur les points d’extensions, effectuer une passe de vérification supplémentaire sur les types inférés par le vérificateur de type du compilateur, ou encore modifier la représentation interne Lambda.</p>
<h2 id="reason">Reason</h2>
<p><img src="//img.linuxfr.org/img/687474703a2f2f7069782e746f696c652d6c696272652e6f72672f75706c6f61642f6f726967696e616c2f313439373033393836372e6a7067/1497039867.jpg" alt="Critique de la raison pure" title="Source : http://pix.toile-libre.org/upload/original/1497039867.jpg"></p>
<p>En dehors de l’évolution du langage lui‐même, un projet inhabituel est né récemment dans les locaux de Facebook<sup id="fnref1"><a href="#fn1">1</a></sup>. Ce projet se nomme <a href="https://facebook.github.io/reason/">Reason</a> et a pour but de rénover la syntaxe d’OCaml. Il a été initié par un petit groupe mené par Jordan Walke (le créateur initial de la bibliothèque <a href="https://facebook.github.io/react/">React</a>).</p>
<h3 id="lobjectif">L’objectif</h3>
<p>La raison de Reason (huhu !) est que la syntaxe d’OCaml rebute certaines personnes. Cependant, OCaml s’inscrit de plus en plus dans le milieu industriel (comme le montrent les exemples de Facebook, mais aussi Jane Street, dans une tout autre mesure). Dans un désir de <em>démocratisation</em>, l’équipe ReasonML décida de créer une nouvelle syntaxe pour OCaml du nom de Reason. Comparé à la syntaxe originale d’OCaml, Reason se rapproche de la syntaxe de JavaScript. Par exemple, les accolades et les points‐virgules font un retour en force :</p>
<pre><code class="OCaml"><span class="k">let</span> <span class="n">hello</span> <span class="n">name_opt</span> <span class="o">=</span>
<span class="k">let</span> <span class="n">name</span> <span class="o">=</span> <span class="k">match</span> <span class="n">name_opt</span> <span class="k">with</span>
<span class="o">|</span> <span class="nc">None</span> <span class="o">-></span> <span class="s2">"world"</span>
<span class="o">|</span> <span class="nc">Some</span> <span class="n">x</span> <span class="o">-></span> <span class="n">x</span> <span class="k">in</span>
<span class="nn">Format</span><span class="p">.</span><span class="n">printf</span> <span class="s2">"Hello %s!"</span> <span class="n">name</span></code></pre>
<p>devient :</p>
<pre><code class="ocaml"><span class="k">let</span> <span class="n">hello</span> <span class="n">name_opt</span> <span class="o">=></span> <span class="o">{</span>
<span class="k">let</span> <span class="n">name</span> <span class="o">=</span> <span class="n">switch</span> <span class="n">name_opt</span> <span class="o">{</span>
<span class="o">|</span> <span class="nc">None</span> <span class="o">=></span> <span class="s2">"world"</span><span class="o">;</span>
<span class="o">|</span> <span class="nc">Some</span> <span class="n">n</span> <span class="o">=></span> <span class="n">n</span><span class="o">;</span>
<span class="o">};</span>
<span class="nn">Format</span><span class="p">.</span><span class="n">printf</span> <span class="s2">"Hello %s!"</span> <span class="n">name</span>
<span class="o">}</span></code></pre>
<p>D’une certaine manière <code>Rust</code> a eu la même idée en proposant une syntaxe très proche du <code>C++</code>. <a href="http://elixir-lang.org/">Elixir</a> rejoint le même objectif dans une autre mesure.</p>
<p>La syntaxe de Reason essaye également d’augmenter la cohérence interne de la syntaxe et de corriger des erreurs historiques. Par exemple, les constructeurs de types se lisent de droite à gauche comme les fonctions dans Reason :</p>
<pre><code class="ocaml"><span class="k">type</span> <span class="n">constructeur_de_type</span> <span class="k">'</span><span class="n">argument</span> <span class="o">=</span> <span class="o">{</span> <span class="n">id</span><span class="o">:</span><span class="kt">int</span><span class="o">,</span> <span class="n">x</span><span class="o">:</span><span class="k">'</span><span class="n">argument</span> <span class="o">}</span></code></pre>
<p>L’objectif est, bien entendu, plus large et a amorcé notamment un élan autour des outils qui peuvent aider le développeur à utiliser OCaml. Le <em>top‐level</em> interactif amélioré <code>utop</code>, qui semble unanimement reconnu comme étant l’outil pour tester du code OCaml, fut réutilisé pour Reason et l’accueil auprès des nouveaux développeurs (extérieurs à la communauté OCaml) fut couronné de succès.</p>
<p>Le service d’aide à l’édition <code>merlin</code>, qui permet d’intégrer la coloration syntaxique, mais aussi l’inférence de type dans les éditeurs, eut aussi son intégration avec Reason et tout ceci apporta une légitimité à la continuation de ces projets pour Reason mais aussi pour OCaml.</p>
<p>Enfin, le gestionnaire de paquets <code>opam</code> reste toujours la pierre angulaire de l’écosystème d’OCaml et donc l’est aussi par définition pour Reason. Ce dernier se voit donc désormais utilisé par des gens n’ayant pas forcément en tête les subtilités de l’écosystème d’OCaml (comme <code>ocamlfind</code>).</p>
<p>Au‐delà de cette nouvelle syntaxe, l’équipe de Reason attache donc une attention particulière à l’environnement de développement d’OCaml. Cela permet notamment d’apporter une réelle critique extérieure aux outils de développement OCaml et en particulier une critique justifiée sur la difficulté de prise en main de ces outils pour un débutant.</p>
<h3 id="ce-quest-reason">Ce qu’est Reason</h3>
<p>Reason n’est ni plus ni moins qu’une option dans le compilateur. Nous parlons ici de l’option <code>-pp</code> qui permet de remplacer la partie frontale du compilateur par un préprocesseur <em>ad hoc</em>. Le préprocesseur Reason prend donc du code Reason en entrée, le transforme en arbre de syntaxe abstrait OCaml et passe cet arbre au compilateur OCaml classique.</p>
<p>Ceci permet entre autres de garder la compatibilité avec l’existant et de profiter à la fois des logiciels et bibliothèques déjà développés en OCaml et de la nouvelle syntaxe Reason, et réciproquement. Il existe d’ailleurs un outil permettant de convertir du code OCaml vers du code Reason !</p>
<p>Partager la partie centrale du compilateur permet également d’utiliser les différents <em>back‐ends</em> disponibles pour OCaml. En particulier, OCaml dispose de deux <em>back‐ends</em> JavaScript : <em>js_of_ocaml</em> et <em>bucklescript</em>. Le premier, <em>js_of_ocaml</em>, est plus ancré dans l’écosystème OCaml, tandis que le second, <em>bucklescript</em>, est plus tourné vers l’écosystème JavaScript et dispose d’une intégration avec <em>npm</em>, un gestionnaire de paquets JavaScript.</p>
<p>Grâce à ces <em>back‐ends</em>, l’équipe ReasonML a pu convertir environ 25 % du code de FaceBook Messenger en code Reason.</p>
<h3 id="un-avenir-imprévisible">Un avenir imprévisible</h3>
<p>On peut cependant s’interroger sur l’interaction de la communauté OCaml existante et de cette nouvelle communauté Reason, bien plus centrée sur le Web, l’écosphère JavaScript et <em>npm</em>. Les atomes crochus n’abondent pas forcément entre ces deux communautés.</p>
<p>Le bon point reste tout de même l’ouverture de l’écosystème d’OCaml à des développeurs qui ne faisaient pas de l’OCaml. Cela permet notamment d’apporter des perspectives neuves et de revitaliser des problématiques de développement parfois oubliées dans l’écosystème OCaml.</p>
<p>Le succès n’est peut‐être pas au rendez‐vous et le projet a encore besoin de faire ses preuves auprès d’un large public (problématique qu’on peut corréler avec <a href="http://hacklang.org/">Hack</a> auprès de ceux qui font du PHP d’ailleurs). Mais le retour ne semble être que bénéfique au final pour l’ensemble des communautés !</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>elle a été extérieure puisqu’elle a été initiée par Facebook alors que ce dernier ne faisait pas encore partie du consortium OCaml. <a href="#fnref1">↩</a></p>
</li>
</ol>
</div></div><div><a href="https://linuxfr.org/news/ocaml-4-04-et-4-05.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/110490/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/ocaml-4-04-et-4-05#comments">ouvrir dans le navigateur</a>
</p>
chiccooctachronYves Bourguignonkantienpalm123SnarkDavy DefaudBenoît SibaudclaudexgascheOntologiapatrick_gDinosaureLucashttps://linuxfr.org/nodes/110490/comments.atomtag:linuxfr.org,2005:News/380962017-07-06T11:29:33+02:002017-07-08T17:10:04+02:00Qui est le coupable ? Le processeur ! Retour sur un bogue important des SkyLake & Kaby Lake IntelLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Certains d’entre vous ont peut‐être vu passer l’information : les derniers processeurs Intel des familles Skylake et Kaby Lake sont victimes d’un bogue lorsque l’<em>hyper‐threading</em> est activé. On trouve par exemple <a href="https://arstechnica.com/information-technology/2017/06/skylake-kaby-lake-chips-have-a-crash-bug-with-hyperthreading-enabled/">un article sur <em>Ars Technica</em></a>, et Debian <a href="https://lists.debian.org/debian-devel/2017/06/msg00308.html">propose des instructions détaillées pour corriger le problème en mettant à jour le microcode (<em>firmware</em>) du processeur</a>.</p>
<p>Cette dépêche propose revenir sur les événements qui ont mené à la découverte du problème. Xavier Leroy le décrit en détail dans un article sur le blog de l’équipe Gallium, dont je proposerai un résumé pour les lecteurs francophones.</p></div><ul><li>lien nᵒ 1 : <a title="https://linuxfr.org/users/kantien/journaux/un-bug-qui-est-le-coupable-le-processeur" hreflang="fr" href="https://linuxfr.org/redirect/100218">Journal à l’origine de la dépêche</a></li><li>lien nᵒ 2 : <a title="http://gallium.inria.fr/blog/intel-skylake-bug/" hreflang="en" href="https://linuxfr.org/redirect/100219">Blog Gallium : « How I find a bug in Intel Skylake processors »</a></li><li>lien nᵒ 3 : <a title="http://www.intel.co.uk/content/dam/www/public/us/en/documents/specification-updates/desktop-6th-gen-core-family-spec-update.pdf" hreflang="en" href="https://linuxfr.org/redirect/100220">Mise à jour des spécifications Intel</a></li><li>lien nᵒ 4 : <a title="https://news.ycombinator.com/item?id=14630183" hreflang="en" href="https://linuxfr.org/redirect/100221">Discussion sur ycombinator</a></li><li>lien nᵒ 5 : <a title="https://tech.ahrefs.com/skylake-bug-a-detective-story-ab1ad2beddcd" hreflang="en" href="https://linuxfr.org/redirect/100226">Skylake bug: a detective story</a></li><li>lien nᵒ 6 : <a title="https://fr.wikipedia.org/wiki/Hyper-Threading" hreflang="fr" href="https://linuxfr.org/redirect/100248">Hyper‐threading sur Wikipédia</a></li></ul><div><p>Tout commence en avril 2016 lorsqu’un SIOU (<em>Serious Industrial OCaml User</em>), comme il les appelle, le contacte en privé pour lui signaler un bogue dans un de leur logiciel : ce dernier subit des erreurs de segmentation de manière aléatoire après un certain temps. Il n’arrive pas à reproduire le bogue sur sa propre machine et le côté aléatoire du bogue lui fait soupçonner un problème matériel chez le client (mémoire vive défectueuse, surchauffe…). Il leur propose de tester leur mémoire et de désactiver l’<em><a href="https://fr.wikipedia.org/wiki/Hyper-Threading">hyper‐threading</a></em>. La mémoire était bonne, mais il ne teste pas la désactivation (ce qui aurait résolu le problème).</p>
<p>De son côté, le client fait ses tests et aboutit aux résultats suivants : le bogue est présent avec la version 4.03 mais pas la 4.02.3 du compilateur OCaml, avec GCC mais pas Clang (l’environnement d’exécution d’OCaml est en C), sur GNU/Linux et Windows mais pas macOS (ce qui se comprend, ce dernier utilisant Clang). Les coupables semblent identifiés : OCaml 4.03 et GCC, et le client suppose qu’il y a une erreur dans le code C de l’environnement d’exécution d’OCaml.</p>
<p>Début mai 2016, le client offre un accès à sa machine à Xavier Leroy pour qu’il puisse identifier le problème. Il analyse des vidages mémoire (<em>dumps</em>) post‐plantage, voit bien des problèmes avec le ramasse‐miettes, mais ne comprend pas ce qui peut causer un tel comportement dans son code. Il fait alors des tests en lançant le programme en parallèle (1, 2, 4, 8 ou 16 instances) et, là, tout devient clair : pas de bogue quand l’<em>hyper‐threading</em> n’est pas utilisé. Ils font des tests en le désactivant dans le BIOS et le problème ne se manifeste plus.</p>
<p>Cela aurait pu en rester là : le client était satisfait de pouvoir utiliser une version de l’environnement d’exécution avec Clang, et Xavier Leroy ne sachant pas comment signaler le problème à Intel en reste là. Mais, début 2017, un autre SIOU fait un <a href="https://caml.inria.fr/mantis/view.php?id=7452">rapport de bogue sur le système de suivi d’OCaml</a>. Les symptômes étaient similaires et la discussion sur le ticket fut la suivante :</p>
<ul>
<li>douze heures après l’ouverture, une des ingénieurs précise que tous les ordinateurs qui ont pu reproduire le bogue ont un processeur de la famille Skylake ;</li>
<li>le lendemain, Xavier Leroy signale son expérience passée et propose de désactiver l’<em>hyper‐threading</em> ;</li>
<li>le jour suivant, un autre ingénieur du SIOU rapporte qu’en désactivant l’<em>hyper‐threading</em> le problème disparaît ;</li>
<li>en parallèle, il constate que si l’environnement d’exécution est compilé avec <code>gcc -O1</code> et non <code>gcc -O2</code> alors le bogue disparaît. Ce qui permet de comprendre pourquoi cela apparaît avec la version 4.03, qui est celle inaugurant l’option <code>-O2</code> par défaut pour l’environnement d’exécution ;</li>
<li>Mark Shinwell contacte des collègues chez Intel et s’occupe de rapporter le problème au support client d’Intel.</li>
</ul><p>Enfin, cinq mois plus tard, Debian publie une mise à jour du microcode des processeurs Intel et Intel publie, en avril, <a href="http://www.intel.co.uk/content/dam/www/public/us/en/documents/specification-updates/desktop-6th-gen-core-family-spec-update.pdf">une mise à jour des spécifications de la 6<sup>e</sup> génération de ses processeurs</a>. On trouve à la page 65 de ce document une mention du problème SKL150 qui était à l’origine de tous ces bogues, présenté en ces termes chez Debian :</p>
<blockquote>
<p>SKL150 - Short loops using both the AH/BH/CH/DH registers and<br>
the corresponding wide register <em>may</em> result in unpredictable<br>
system behavior. Requires both logical processors of the same<br>
core (i.e. sibling hyperthreads) to be active to trigger, as<br>
well as a “complex set of micro‐architectural conditions”.</p>
</blockquote>
<p>Pour ceux que cela intéresse et qui comprennent l’assembleur (ce qui n’est pas mon cas), le problème venait de ce bout de code du <a href="https://fr.wikipedia.org/wiki/Ramasse-miettes_(informatique)">ramasse‐miettes</a> d’OCaml :</p>
<pre><code class="C"><span class="n">hd</span> <span class="o">=</span> <span class="n">Hd_hp</span> <span class="p">(</span><span class="n">hp</span><span class="p">);</span>
<span class="cm">/*...*/</span>
<span class="n">Hd_hp</span> <span class="p">(</span><span class="n">hp</span><span class="p">)</span> <span class="o">=</span> <span class="n">Whitehd_hd</span> <span class="p">(</span><span class="n">hd</span><span class="p">);</span></code></pre>
<p>Qui après expansion des macros donne :</p>
<pre><code class="C"><span class="n">hd</span> <span class="o">=</span> <span class="o">*</span><span class="n">hp</span><span class="p">;</span>
<span class="cm">/*...*/</span>
<span class="o">*</span><span class="n">hp</span> <span class="o">=</span> <span class="n">hd</span> <span class="o">&</span> <span class="o">~</span><span class="mh">0x300</span><span class="p">;</span></code></pre>
<p>Avec Clang, cela donnait :</p>
<pre><code class="asm"><span class="nf">movq</span> <span class="p">(</span><span class="o">%</span><span class="nb">rbx</span><span class="p">),</span> <span class="o">%</span><span class="nb">rax</span>
<span class="err">[</span><span class="nf">...</span><span class="p">]</span>
<span class="nf">andq</span> <span class="kc">$</span><span class="o">-</span><span class="mi">769</span><span class="p">,</span> <span class="o">%</span><span class="nb">rax</span> <span class="err">#</span> <span class="nv">imm</span> <span class="err">=</span> <span class="mh">0xFFFFFFFFFFFFFCFF</span>
<span class="nf">movq</span> <span class="o">%</span><span class="nb">rax</span><span class="p">,</span> <span class="p">(</span><span class="o">%</span><span class="nb">rbx</span><span class="p">)</span></code></pre>
<p>Tandis que le code optimisé de GCC donnait :</p>
<pre><code class="asm"><span class="nf">movq</span> <span class="p">(</span><span class="o">%</span><span class="nb">rdi</span><span class="p">),</span> <span class="o">%</span><span class="nb">rax</span>
<span class="err">[</span><span class="nf">...</span><span class="p">]</span>
<span class="nf">andb</span> <span class="kc">$</span><span class="mi">252</span><span class="p">,</span> <span class="o">%</span><span class="nb">ah</span>
<span class="nf">movq</span> <span class="o">%</span><span class="nb">rax</span><span class="p">,</span> <span class="p">(</span><span class="o">%</span><span class="nb">rdi</span><span class="p">)</span></code></pre>
<p>Qui pouvait lever le bogue du processeur s’il se trouvait dans une petite boucle ?</p>
<p>Ce bogue sur ces processeurs impacte tous les systèmes d’exploitation. Le correctif du microcode pour la génération Skylake existe donc depuis avril, car Intel distribue ses mises à jour à toutes et tous, permettant aux mainteneurs des distributions de réaliser l’empaquetage afin de les rendre disponibles.</p>
<p>Cependant, il n’en va pas de même pour la génération Kaby Lake, pour laquelle Intel ne distribue ses correctifs de microcodes qu’aux seuls constructeurs ou assembleurs. Il résulte de cette situation une grande disparité des disponibilités pour cette mise à jour : certains constructeurs l’ont déjà proposée, d’autres ne le font pas.</p>
<p>Au final, il semblerait que Skylake se soit transformé en Skyfall et que la légendaire crainte gauloise que le ciel leur tombe sur la tête était fondée ! :-D</p></div><div><a href="https://linuxfr.org/news/qui-est-le-coupable-le-processeur-retour-sur-un-bogue-important-des-skylake-kaby-lake-intel.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/112231/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/qui-est-le-coupable-le-processeur-retour-sur-un-bogue-important-des-skylake-kaby-lake-intel#comments">ouvrir dans le navigateur</a>
</p>
kantienbubar🦥Benoît SibaudDavy DefaudZeroHeureNils Ratusznikpatrick_ghttps://linuxfr.org/nodes/112231/comments.atom