Derniers messages sur Zeste de Savoirhttps://zestedesavoir.com/forums/2021-04-02T19:48:14+02:00Les derniers messages parus sur le forum de Zeste de Savoir.Définition de type c++, message #2329162021-04-02T19:48:14+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15209/definition-de-type-c/?page=1#p232916<p>Tu devrais pouvoir faire une classe abstraite Foo dont héritent les sous-classes A, B et C (qui contient une liste de Foo).</p>Définition de type c++, message #2328982021-04-02T13:41:50+02:00Vildevil/@Vildevilhttps://zestedesavoir.com/forums/sujet/15209/definition-de-type-c/?page=1#p232898<p>Merci, je ne connaissais pas du tout, c’est bien pratique ! Je pense pouvoir régler mon problème avec ça. Encore merci</p>Définition de type c++, message #2328952021-04-02T13:22:54+02:00Ksass`Peuk/@Ksass%60Peukhttps://zestedesavoir.com/forums/sujet/15209/definition-de-type-c/?page=1#p232895<p>Lu’!</p>
<p>En complément, il faut voir par contre si c’est effectivement la manière la plus idiomatique de régler ton problème concret en C++.</p>Définition de type c++, message #2328942021-04-02T13:21:29+02:00jo_link_noir/@jo_link_noirhttps://zestedesavoir.com/forums/sujet/15209/definition-de-type-c/?page=1#p232894<p><code>std::variant</code> est ce qui correspond le plus. Mais celle du standard ne supporte pas les structures récursives du coup il faut soit utiliser une implémentation alternative (on en trouve facilement sur github) soit utiliser une structure qui a comme membre un pointeur sur elle-même: <code>struct Foo { std::variant<A, B, Foo* / std::unique_ptr<Foo> / std::vector<Foo> / etc> }</code>.</p>Définition de type c++, message #2328932021-04-02T12:54:59+02:00Vildevil/@Vildevilhttps://zestedesavoir.com/forums/sujet/15209/definition-de-type-c/?page=1#p232893<p>Bonjour, en ce moment je suis sur un petit projet en c++, et je me demandais quelle était la manière la plus optimisé pour reproduire ce comportement, issu de ocaml en c++ :</p>
<div class="hljs-code-div hljs-code-ocaml"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span></div><pre><code class="hljs language-ocaml"><span class="hljs-keyword">type</span> foo =
| <span class="hljs-type">A</span>
| <span class="hljs-type">B</span>
| <span class="hljs-type">C</span> <span class="hljs-keyword">of</span> foo <span class="hljs-built_in">list</span>
</code></pre></div>
<p>Je trouve en effet que la structure n’est pas très adapté puisque je suis obligé de créer d’abord une énumération puis une union dans la structure ce qui n’est pas très pratique. Si quelqu’un à une idée, je suis preneur.</p>Aide exercice Type abstraits et modules, message #2290612020-12-12T14:50:03+01:00gasche/@gaschehttps://zestedesavoir.com/forums/sujet/14835/aide-exercice-type-abstraits-et-modules/?page=1#p229061<p>Deux remarques:</p>
<ul>
<li>
<p>Je stresse quand je vois <code>[m]</code> dans un pattern, et que les autres cas ne sont pas gérés.
Même si ça marchotte aujourd’hui grâce à ton <code>| _ -> false</code>, c’est un nid à bugs pour la suite quand ton code changera. Je te conseille vivement d’écrire le code avec seulement un filtrage sur l’expression régulière, et éventuellement des sous-filtrages sur le mot dans les cas où c’est utile.</p>
</li>
<li>
<p>Le cas du produit est faux car il suppose que <code>x</code> ne mange qu’un seul caractère, mais <code>x</code> peut être une expression qui matche plusieurs symboles. Considérer <code>Produit(Produit(Symbole 'a', Symbole 'b'), Symbole 'c')</code> par exemple.</p>
</li>
</ul>Aide exercice Type abstraits et modules, message #2290512020-12-12T12:36:21+01:00mateoben/@mateobenhttps://zestedesavoir.com/forums/sujet/14835/aide-exercice-type-abstraits-et-modules/?page=1#p229051<p>Merci.
J’avance</p>
<div class="hljs-code-div hljs-code-Ocaml"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span><span data-count="13"></span><span data-count="14"></span><span data-count="15"></span><span data-count="16"></span><span data-count="17"></span><span data-count="18"></span><span data-count="19"></span><span data-count="20"></span><span data-count="21"></span><span data-count="22"></span><span data-count="23"></span></div><pre><code class="hljs language-Ocaml"><span class="hljs-keyword">let</span> <span class="hljs-keyword">rec</span> accept mot expReguliere = <span class="hljs-keyword">match</span> (mot,expReguliere) <span class="hljs-keyword">with</span>
|[m],<span class="hljs-type">Symbole</span> x -> x = m
|mot,<span class="hljs-type">Union</span> (x,y) -> (accept mot x) || (accept mot y)
|m::mot,<span class="hljs-type">Produit</span> (x,y) -> (accept [m] x) && (accept mot y)
|m::mot,<span class="hljs-type">Repetition</span> x -> (accept [m] x) && (accept mot x)
|_-> <span class="hljs-literal">false</span>
<span class="hljs-type">C'est</span> faux pour répétition.
<span class="hljs-type">Arden</span> nous donne :
<span class="hljs-type">L1</span> = a*λ
= a.<span class="hljs-type">L1</span> + λ
<span class="hljs-comment">(*
accept ['b';'a'] (Produit(Symbole 'b', Symbole 'a'))
not accept ['a';'b'] (Produit(Symbole 'b', Symbole 'a'))
accept ['a'] (Union (Symbole 'b', Symbole 'a'))
accept ['a';'b';'b'] (Produit(Symbole 'a', Repetition (Symbole 'b')))
accept ['a';'b';'d'] (Produit(Symbole 'a', Produit(Union (Symbole 'b', Symbole 'c'), Repetition (Symbole 'd'))))
*)</span>
</code></pre></div>Aide exercice Type abstraits et modules, message #2290462020-12-12T11:47:15+01:00Berdes/@Berdeshttps://zestedesavoir.com/forums/sujet/14835/aide-exercice-type-abstraits-et-modules/?page=1#p229046<p><code>split</code> peut s’implémenter assez facilement récursivement, surtout avec les fonctions créés plus tôt dans la partie 1. Hint: essaye de voire comment tu peux transformer le retour de <code>split [2; 3]</code> en le retour de <code>split [1; 2; 3]</code>.</p>
<p>Une expression régulière permet de définir un schéma et d’ensuite vérifier si une entrée suis ce schéma. C’est typiquement utilisé sur les chaînes de caractères, par exemple pour vérifier si une chaîne de caractères ressemble à une adresse email<sup id="fnref-1-fvnx5fjfb"><a href="#fn-1-fvnx5fjfb" class="footnote-ref">1</a></sup>.</p>
<p>Une expression régulière se défini par composition d’expression régulières plus simples, jusqu’à ce qu’on n’utilise que les briques de base. Ici, la brique de base est <code>Symbole 'a</code> qui accepte un unique symbole. <code>Union</code>, <code>Produit</code> et <code>Repetition</code> sont utilisés pour composer des expressions régulière en une expression régulière plus complexe.</p>
<p>Par exemple, on peut vouloir réaliser la vérification suivante: la chaîne de caractère en entrée doit commencer par la lettre 'a’, suivi de soit 'b’, soit 'c' et enfin doit avoir plusieurs 'd’. Dans cet exemple "acddd" est valide, "abd" l’est aussi, mais "abc" et "bdd" ne le sont pas.</p>
<p>Dans cet exemple, le "suivi de" correspond à l’opération de <code>Produit</code> et le "soit x, soit y" correspond à l’opération d'<code>Union</code>. L’expression que j’ai décrite peut donc s’écrire <code>Produit(Symbole 'a', Produit(Union (Symbole 'b', Symbole 'c'), Repetition (Symbole 'd')))</code>.</p>
<p>Si j’ai une recommandation à avoir pour l’implémentation, c’est que tu écrives tout plein de tests les plus simple possible pour savoir ce qui fonctionne et ce qui ne fonctionne pas. Par exemple <code>accept ['a'] (Symbole 'a')</code> doit retourner <code>True</code> alors que <code>accept ['a';'a'] (Symbole 'a')</code> doit retourner <code>False</code>.</p>
<p>L’implémentation de chaque cas va en difficulté croissante: <code>Symbole</code> est plus simple à implémenter que <code>Union</code>, qui est plus simple que <code>Produit</code>, qui est plus simple que <code>Repetition</code>. Donc il vaut mieux commencer par des tests d’expression régulière utilisant <code>Symbole</code> uniquement, puis y ajouter <code>Union</code>, etc.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn-1-fvnx5fjfb">C’est en faite une mauvaise idée d’utiliser un expression régulière pour valider une adresse email, notamment parce que le format d’une adresse email est <strong>beaucoup</strong> complexe que ce qui est habituellement utilisé.<a href="#fnref-1-fvnx5fjfb" class="footnote-backref" title="Retourner au texte de la note 1">↩</a></li>
</ol>
</div>Aide exercice Type abstraits et modules, message #2290452020-12-12T11:40:27+01:00gasche/@gaschehttps://zestedesavoir.com/forums/sujet/14835/aide-exercice-type-abstraits-et-modules/?page=1#p229045<p>Effectivement le code que tu as écrit ne fait pas ce qui est demandé. Je ne sais pas si tu as bien compris la définition de "l’ensemble des mots reconnus par une expression régulière" donné dans le sujet, mais des petits exemples pourraient aider:</p>
<ul>
<li><code>accept ['a'] (Symbole 'a')</code></li>
<li><code>not (accept ['b'; 'a'] (Symbole 'a'))</code> (ce test ne passe pas sur ton code)</li>
<li><code>accept ['a'] (Union (Symbole 'a', Symbole 'b'))</code> (ce test ne passe pas)</li>
<li><code>accept ['a'; 'b'] (Produit (Symbole 'a', Symbole 'b'))</code> (ce test ne passe pas)</li>
</ul>
<p>Je te conseille d’essayer de comprendre comment interpréter correctemenet <code>Symbole</code>, <code>Union</code> et <code>Produit</code> pour commencer, et réfléchir seulement ensuite à <code>Repetition</code>.</p>Aide exercice Type abstraits et modules, message #2290422020-12-12T10:45:38+01:00mateoben/@mateobenhttps://zestedesavoir.com/forums/sujet/14835/aide-exercice-type-abstraits-et-modules/?page=1#p229042<p>Alors j’ai réussi à faire toute la première partie sauf la fonction split.</p>
<p>Ensuite pour la deuxième, je comprend que l’on forme un type particulier formé d’expressions régulières de n’importe quel type 'a re.
Ce type peut être un symbole 'a, une Union d’expressions régulières (’a re,’a re)</p>
<p>Et en reprenant l’explication, j’ai réussi à avancer un peu <img src="/static/smileys/svg/smile.svg" alt=":)" class="smiley">
Je ne dis pas que le code fait ce qui est demandé, à savoir tester si le mot est reconnu par l’expression régulière, mais au moins ça compile</p>
<div class="hljs-code-div hljs-code-Ocaml"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span></div><pre><code class="hljs language-Ocaml"><span class="hljs-keyword">type</span> <span class="hljs-symbol">'a</span> re =
| <span class="hljs-type">Symbole</span> <span class="hljs-keyword">of</span> <span class="hljs-symbol">'a</span>
| <span class="hljs-type">Union</span> <span class="hljs-keyword">of</span> <span class="hljs-symbol">'a</span> re * <span class="hljs-symbol">'a</span> re
| <span class="hljs-type">Produit</span> <span class="hljs-keyword">of</span> <span class="hljs-symbol">'a</span> re * <span class="hljs-symbol">'a</span> re
| <span class="hljs-type">Repetition</span> <span class="hljs-keyword">of</span> <span class="hljs-symbol">'a</span> re
</code></pre></div>
<div class="hljs-code-div hljs-code-Ocaml"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span></div><pre><code class="hljs language-Ocaml"><span class="hljs-keyword">let</span> <span class="hljs-keyword">rec</span> accept l expReguliere = <span class="hljs-keyword">match</span> expReguliere <span class="hljs-keyword">with</span>
|<span class="hljs-type">Symbole</span> x -> exists (<span class="hljs-keyword">fun</span> y -> y=x) l
|<span class="hljs-type">Union</span> (x,y) -> (accept l x) && (accept l y)
|<span class="hljs-type">Produit</span> (x,y) -> (accept l x) && (accept l y)
|<span class="hljs-type">Repetition</span> x -> accept l x
</code></pre></div>
<p>Ce sont des notions difficiles à assimiler..</p>Aide exercice Type abstraits et modules, message #2290412020-12-12T00:58:29+01:00Berdes/@Berdeshttps://zestedesavoir.com/forums/sujet/14835/aide-exercice-type-abstraits-et-modules/?page=1#p229041<p>Est-ce que tu peux expliquer ce que tu ne comprends pas dans la deuxième partie? Ou au moins ce que tu comprends.</p>Aide exercice Type abstraits et modules, message #2290402020-12-12T00:01:30+01:00mateoben/@mateobenhttps://zestedesavoir.com/forums/sujet/14835/aide-exercice-type-abstraits-et-modules/?page=1#p229040<p>Bonjour.
Je viens vers vous car j’aborde un nouveau thème et je suis vraiment perdu sur ce qu’il faut faire
La première partie se passe bien</p>
<figure><img src="/media/galleries/13144/71b8d18b-9954-4168-b5ce-50d80a4ae9f9.png" alt="image.png"><figcaption>image.png</figcaption></figure>
<p>Mais pour la deuxième partie je ne comprend pas ce qui est demandé :</p>
<figure><img src="/media/galleries/13144/146b59b0-c395-4f1b-9416-32804c3a37bb.png" alt="image.png"><figcaption>image.png</figcaption></figure>Que se passe-t-il avec camlp4 ?, message #2281612020-11-16T23:36:54+01:00titus/@titushttps://zestedesavoir.com/forums/sujet/14672/que-se-passe-t-il-avec-camlp4/?page=1#p228161<p>Merci pour ta réponse <a href="/membres/voir/gasche/" rel="nofollow" class="ping ping-link">@<span class="ping-username">gasche</span></a>.</p>
<blockquote>
<p> Cette transition a commencé avec OCaml 4.01 en Septembre 2013, ce n’est pas nouveau; ton étonnement suggère que tu n’es pas un utilisateur actif de versions à jour d’OCaml</p>
</blockquote>
<p>En effet. J’ai souvent eu l’impression, en regardant de loin les nouvelles versions d’OCaml, que les nouveautés ne concernaient que des gens « du milieu » et que j’avais encore beaucoup à faire avec les éléments de base du langage dont je dispose… ce qui explique que je ne traîne pas souvent sur ocaml.org (et c’est sûrement un tord !)</p>
<blockquote>
<p>Dans ce contexte, sur le moyen/long terme le choix le plus sain serait d’éviter d’utiliser l’extension syntaxique pour les streams (<code>[< ... >]</code> et <code>parser</code>).</p>
</blockquote>
<p>C’est noté ! J’ai pu lire ici et là par le passé que camlp4 était un outil intéressant justement pour cette extension syntaxique. Mais je comprends un peu mieux les raisons qui ont poussé la communauté OCaml à ne plus maintenir camlp4 en lisant <a href="https://discuss.ocaml.org/t/the-end-of-camlp4/4216/22">ton post</a> sur ocaml.org.</p>
<p>Et pour conclure sur le fond « technique » de ce topic, j’opte pour ta solution long terme en utilisant le module Stream de OCaml. Pour des parsers simples, la fonction Stream.next fera bien le travail dans un premier temps <img src="/static/smileys/svg/smile.svg" alt=":)" class="smiley"></p>Que se passe-t-il avec camlp4 ?, message #2275442020-11-01T12:04:11+01:00gasche/@gaschehttps://zestedesavoir.com/forums/sujet/14672/que-se-passe-t-il-avec-camlp4/?page=1#p227544<p>Il y a plusieurs choses différentes à discuter:</p>
<ul>
<li>
<p>Tu utilises des méthodes de compilation qui sont fragiles (elles supposent que <code>camlp4o.cma</code> est installé avec la bibliothèque standard, alors que c’est maintenant un paquet séparé) et d’un autre âge (à minima utiliser <code>ocamlfind</code> qui abstrait sur ces détails). C’est facile à corriger et tu auras du code qui marche en réponse à ce fil.</p>
</li>
<li>
<p>En effet, globalement camlp4 est déprécié aujourd’hui et n’est plus considéré comme une bonne solution. La communauté d’utilisateurs OCaml recommande ppx.</p>
<p>Cette transition a commencé avec OCaml 4.01 en Septembre 2013, ce n’est pas nouveau; ton étonnement suggère que tu n’es pas un utilisateur actif de versions à jour d’OCaml, ce qui n’a rien de honteux, il faut que ça se passe bien même pour des utilisateurs occasionnels ou très non-spécialistes.</p>
<p>Concrètement, Camlp4 est de moins en moins maintenu à jour depuis quelques années (tu as vu l’annonce de la fin du support en août 2019; c’est en fait toujours maintenu mais à petites doses), et finira par arrêter d’être facile à utilier sur une version à jour de OCaml. C’est utilisable aujourd’hui, mais pas une bonne approche sur le long terme.</p>
</li>
<li>
<p>Dans ce contexte, sur le moyen/long terme le choix le plus sain serait d’éviter d’utiliser l’extension syntaxique pour les streams (<code>[< ... >]</code> et <code>parser</code>). Ça veut dire soit faire le parsing sur les flux directement (en utilisant <code>Stream</code> ou une autre bibliothèque), ce qui est plutôt facile pour des parsers simples, soit utiliser une autre approche de parsing, par exemple Menhir ou des combinateurs de parsing.</p>
</li>
</ul>
<p>Ceci étant dit, le plus simple pour corriger ton problème à court terme est d’utiliser <code>ocamlfind</code>, qui sait où trouver <code>camlp4o.cma</code>. Pour compiler un projet, il suffit de dire à ton outil de build d’ajouter le paquet <code>camlp4</code>. Dans le toplevel interactif:</p>
<ol>
<li>Si tu utilises <code>ocaml</code>, faire <code>#use "topfind";;</code> pour charger le support ocamlfind, et ensuite <code>#camlp4o;;</code> qui active les extensions syntaxiques dans le toplevel.</li>
<li>Si tu utilises <code>utop</code>, un toplevel grandement amélioré (je t’invite à essayer), <code>#use "topfind";;</code> n’est plus nécessaire, utiliser <code>#camlp4o;;</code> directement devrait suffire.</li>
</ol>Que se passe-t-il avec camlp4 ?, message #2275332020-10-31T14:56:04+01:00titus/@titushttps://zestedesavoir.com/forums/sujet/14672/que-se-passe-t-il-avec-camlp4/?page=1#p227533<p>Bonjour,</p>
<p>Récemment, j’ai souhaité me replonger dans l’interprétation, en commençant par me rafraîchir la mémoire sur l’analyse lexicale avec OCaml (version 4.08.1) et la manipulation des streams.</p>
<p>Je rencontre une erreur au chargement des modules usuellement appelés dans ce contexte :</p>
<div class="hljs-code-div hljs-code-ocaml"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span></div><pre><code class="hljs language-ocaml">#load <span class="hljs-string">"dynlink.cma"</span> ;;
#load <span class="hljs-string">"camlp4o.cma"</span> ;;
<span class="hljs-type">Cannot</span> find file camlp4o.cma.
</code></pre></div>
<p><code>camlp4</code> ne semblait pas installé, j’ai donc lancé <code>opam install camlp4</code> suivi de <code>opam update</code> et <code>opam upgrade</code>.
Il me semble que l’installation s’est bien passée :</p>
<div class="hljs-code-div hljs-code-bash"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span></div><pre><code class="hljs language-bash">$ ocamlfind query camlp4
/home/titus/.opam/4.08.1/lib/ocaml/camlp4
</code></pre></div>
<p>Cependant, je rencontre la même erreur au chargement de <code>camlp4o.cma</code> dans le top-level OCaml. Dans le doute, j’ai voulu m’assurer que je ne travaillais pas sur une ancienne version d’OCaml mais il semblerait que non :</p>
<div class="hljs-code-div hljs-code-bash"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span></div><pre><code class="hljs language-bash">$ opam switch show
4.08.1
</code></pre></div>
<p>Cela correspond bien à la version pour laquelle camlp4 a été installée.</p>
<p>D’où une première question : mon installation et mon appel à camlp4 sont-ils corrects ? J’utilise opam très ponctuellement et quelque chose m’a peut-être échappé.</p>
<p>J’ai ensuite, de façon prétentieuse, supposé que le problème ne venait pas de moi. En faisant des recherches, je suis tombé sur un <a href="https://discuss.ocaml.org/t/the-end-of-camlp4/4216">post</a> sur ocaml.org. Ce message explique que camlp4 arrive en fin de vie et sera à terme remplacé par un outil du nom de <code>ppx</code>.</p>
<p>Je comprends du dernier paragraphe que les développeurs OCaml ne considèrent plus les streams comme un outil pertinent pour l’analyse lexicale, et nous encouragent à explorer d’autres solutions (mais j’ai peut-être mal compris…)</p>
<p>Cela signifie-t-il qu’il sera désormais impossible de faire tourner des codes appelant des pattern matching sur des stream, ou qui utilisent la notation <code>[< >]</code> ?</p>
<p>Y a-t-il un lien entre cette annonce (qui pourtant indique qu’une version de camlp4 est disponible pour OCaml 4.08) et mon problème ?</p>
<p>Merci d’avoir pris le temps de me lire et merci par avance pour vos réponses ! <img src="/static/smileys/svg/smile.svg" alt=":)" class="smiley"></p>OCaml et type option : des variables dans un mini interpréteur, message #2210752020-05-21T15:46:13+02:00otini/@otinihttps://zestedesavoir.com/forums/sujet/14089/ocaml-et-type-option-des-variables-dans-un-mini-interpreteur/?page=1#p221075<p>Donc une monade de lecture, c’est une technique de code qui repose sur le type suivant :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span></div><pre><code class="hljs language-ocaml"><span class="hljs-keyword">type</span> <span class="hljs-symbol">'a</span> m = env -> <span class="hljs-symbol">'a</span>
</code></pre></div>
<p>où <code>env</code> est le type <code>(string * int) list</code> (par exemple). Un <code>'a m</code> est simplement une fonction qui prend un environnement et renvoie un <code>'a</code>. Maintenant, supposons que c’est effectivement une monade et qu’on a un <code>return</code> et un <em>bind</em> pour ce type.</p>
<p>J’ai repris ton code d’évaluation d’expressions et l’ai modifié pour qu’il utilise une monade de lecture, au lieu de passer <code>l</code> en argument d’<code>eval</code>. Au passage, j’ai enlevé le type option, parce qu’avoir deux monades dans le même code n’est pas très pratique, en particulier en OCaml. Maintenant, si une variable n’est pas trouvée dans l’environnement, <code>eval</code> va lever une exception <code>Not_found</code>.</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-ocaml"><span class="hljs-keyword">type</span> env = (<span class="hljs-built_in">string</span> * <span class="hljs-built_in">int</span>) <span class="hljs-built_in">list</span>
<span class="hljs-keyword">let</span> <span class="hljs-keyword">rec</span> find key = <span class="hljs-keyword">function</span>
| <span class="hljs-literal">[]</span> -> raise <span class="hljs-type">Not_found</span>
| (key', v) :: r -> <span class="hljs-keyword">if</span> key = key' <span class="hljs-keyword">then</span> v <span class="hljs-keyword">else</span> find key r
<span class="hljs-keyword">module</span> <span class="hljs-type">Reader</span> : <span class="hljs-keyword">sig</span>
<span class="hljs-keyword">type</span> <span class="hljs-symbol">'a</span> m
<span class="hljs-keyword">val</span> (>>=) : <span class="hljs-symbol">'a</span> m -> (<span class="hljs-symbol">'a</span> -> <span class="hljs-symbol">'b</span> m) -> <span class="hljs-symbol">'b</span> m
<span class="hljs-keyword">val</span> return : <span class="hljs-symbol">'a</span> -> <span class="hljs-symbol">'a</span> m
<span class="hljs-keyword">end</span> = <span class="hljs-keyword">struct</span>
<span class="hljs-keyword">type</span> <span class="hljs-symbol">'a</span> m = env -> <span class="hljs-symbol">'a</span>
<span class="hljs-keyword">let</span> return x = <span class="hljs-comment">(* ... *)</span>
<span class="hljs-keyword">let</span> (>>=) x f = <span class="hljs-comment">(* ... *)</span>
<span class="hljs-keyword">end</span>
<span class="hljs-keyword">open</span> <span class="hljs-type">Reader</span>
<span class="hljs-keyword">type</span> expr =
| <span class="hljs-type">Const</span> <span class="hljs-keyword">of</span> <span class="hljs-built_in">int</span>
| <span class="hljs-type">Add</span> <span class="hljs-keyword">of</span> expr * expr
| <span class="hljs-type">Neg</span> <span class="hljs-keyword">of</span> expr
| <span class="hljs-type">Var</span> <span class="hljs-keyword">of</span> <span class="hljs-built_in">string</span>
<span class="hljs-keyword">let</span> <span class="hljs-keyword">rec</span> eval (e : expr) : <span class="hljs-built_in">int</span> m = <span class="hljs-keyword">match</span> e <span class="hljs-keyword">with</span>
| <span class="hljs-type">Const</span> n -> return n
| <span class="hljs-type">Var</span> v -> find v
| <span class="hljs-type">Neg</span> e1 ->
eval e1 >>= <span class="hljs-keyword">fun</span> x -> return (-x)
| <span class="hljs-type">Add</span> (e1, e2) ->
eval e1 >>= <span class="hljs-keyword">fun</span> x ->
eval e2 >>= <span class="hljs-keyword">fun</span> y ->
return (x + y)
</code></pre></div>
<p>De façon assez agréable, il n’y a presque rien à modifier par rapport à ton programme où la monade était <code>option</code>. <img src="/static/smileys/svg/magicien.svg" alt=":magicien:" class="smiley"> À présent, le passage de l’environnement dans <code>eval</code> est implicite et laissé aux fonctions monadiques. Le nouveau type de <code>eval</code> est <code>expr -> int m</code>, c’est-à-dire <code>expr -> env -> int</code>. Presque le même qu’avant, en somme.</p>
<p>Tu remarques qu’on peut voir <code>find</code> comme étant de type <code>string -> int m</code>.</p>
<p>J’ai pas mis l’implémentation de <code>return</code> et <code>(>>=)</code> parce que ça peut être un exercice rigolo <img src="/static/smileys/svg/langue.svg" alt=":p" class="smiley"></p>
<p>Bon, comme annoncé, pas de changements révolutionnaires dans cet exemple. Mais parfois, en remarquant que les opérations que tu fais relèvent des monades, tu peux sérieusement clarifier et raccourcir ton code.</p>OCaml et type option : des variables dans un mini interpréteur, message #2210602020-05-21T12:13:38+02:00otini/@otinihttps://zestedesavoir.com/forums/sujet/14089/ocaml-et-type-option-des-variables-dans-un-mini-interpreteur/?page=1#p221060<p>Le code est correct, mais dans l’esprit, il me semblerait plus pertinent de manipuler une pile de type <code>int list</code> plutôt que <code>int option list</code>. En effet, dès qu’on a un <code>None</code> sur la pile, ça veut dire que 1. quelque chose s’est mal passé et 2. toute opération utilisant le résultat va mal se passer aussi. Donc autant court-circuiter tout le reste des calculs et remonter une erreur. Ce que le type <code>option</code>, manipulé comme une monade, permet justement de faire facilement.</p>
<blockquote>
<p>Pour m’entraîner à ce concept de monades qui, si je comprends bien, permet de séparer proprement la propagation d’un résultat et la gestion des erreurs</p>
</blockquote>
<blockquote>
<p>Finalement, en OCaml, monades et type option sont donc systématiquement liés ?</p>
</blockquote>
<p>Pas nécessairement. Les monades sont une façon de programmer qui permet de rendre implicite du <em>code auxiliaire</em> dans une <em>séquence d’opérations</em>. Ce que j’appelle « code auxiliaire » c’est des actions mécaniques qu’on a envie d’écrire une bonne fois pour toutes et de ne plus avoir à gérer. Ça peut être des choses aussi variées que :</p>
<ul>
<li>la gestion d’erreurs (type <code>option</code>, type <code>('res, 'err) maybe_error = Ok of 'res | Error of 'err</code>) ;</li>
<li>la tenue à jour d’un état qui peut évoluer au cours des opérations, sans pour autant devoir utiliser une variable mutable (monade d’état). Exemples : la pile d’une machine à pile (eh oui !), un journal qui enregistre chaque opération réalisée. Ça peut aussi être un état en lecture seule, comme l’environnement <code>l</code> de ton premier message.</li>
<li>Appliquer une suite d’opérations qui peuvent chacune renvoyer plusieurs valeurs (si on a du non-déterminisme, ou des calculs parallèles) en laissant une monade gérer les multiples états intermédiaires ;</li>
<li>en programmation concurrente, si on a un type <code>'a thread</code> qui représente un thread qui, quand il aura terminé, renverra un <code>'a</code> ; on peut demander à faire l’opération <code>f</code> de type <code>'a -> 'b</code> sur le futur résultat en question. On obtient alors un <code>'b thread</code>. Autrement dit, <code>thread</code> est une monade.</li>
<li>Je suis à peu près sûr que j’en oublie.</li>
</ul>
<p>Concrètement, une monade se résume à un type paramétré <code>'a m</code> (comme par exemple <code>'a option</code>) et à l’existence de deux fonctions :</p>
<ul>
<li>une fonction de type <code>'a m -> ('a -> 'b m) -> 'b m</code>, généralement appelée <code>>>=</code> ou <code>bind</code> ;</li>
<li>une fonction de type <code>'a -> 'a m</code>, généralement appelée <code>return</code>.</li>
</ul>
<p>Ces fonctions doivent être reliées par quelques propriétés simples pour qu’on considère qu’on a vraiment une monade mais je laisse ça de côté, on peut le trouver partout et c’est pas très intéressant.</p>
<p>J’essaierai de donner un exemple d’une monade de lecture un peu plus tard.</p>OCaml et type option : des variables dans un mini interpréteur, message #2209552020-05-19T11:50:13+02:00titus/@titushttps://zestedesavoir.com/forums/sujet/14089/ocaml-et-type-option-des-variables-dans-un-mini-interpreteur/?page=1#p220955<p>Merci pour vos réponses. Effectivement gasche, ta première proposition est une solution courante en OCaml, je n’y avais pas pensé dans ce contexte.</p>
<p>Pour m’entraîner à ce concept de monades qui, si je comprends bien, permet de séparer proprement la propagation d’un résultat et la gestion des erreurs, j’ai essayé de « monadiser » un code qui parse des maths à pile.</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-ocaml"><span class="hljs-keyword">open</span> <span class="hljs-type">Genlex</span>
<span class="hljs-keyword">let</span> (>>=) x f = <span class="hljs-keyword">match</span> x <span class="hljs-keyword">with</span>
| <span class="hljs-type">None</span> -> <span class="hljs-type">None</span>
| <span class="hljs-type">Some</span> y -> f y
<span class="hljs-keyword">let</span> lexer chaine =
<span class="hljs-keyword">let</span> jetons = [<span class="hljs-string">"+"</span> ; <span class="hljs-string">"-"</span> ; <span class="hljs-string">"*"</span> ; <span class="hljs-string">"/"</span>] <span class="hljs-keyword">in</span>
make_lexer jetons (<span class="hljs-type">Stream</span>.of_string chaine)
<span class="hljs-keyword">let</span> calcul op a b = <span class="hljs-keyword">match</span> op <span class="hljs-keyword">with</span>
| <span class="hljs-string">"+"</span> -> <span class="hljs-type">Some</span> (a+b)
| <span class="hljs-string">"-"</span> -> <span class="hljs-type">Some</span> (a-b)
| <span class="hljs-string">"*"</span> -> <span class="hljs-type">Some</span> (a*b)
| <span class="hljs-string">"/"</span> -> <span class="hljs-keyword">if</span> b = <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> <span class="hljs-type">None</span> <span class="hljs-keyword">else</span> <span class="hljs-type">Some</span> (a/b)
<span class="hljs-keyword">let</span> <span class="hljs-keyword">rec</span> parse pile stream = <span class="hljs-keyword">match</span> stream <span class="hljs-keyword">with</span> <span class="hljs-keyword">parser</span>
| [< <span class="hljs-string">'(Int n) ; r >] -> parse ((Some n) :: pile) r
| [< '</span>(<span class="hljs-type">Kwd</span> op) ; r >] -> <span class="hljs-keyword">let</span> x1::x2::xs = pile <span class="hljs-keyword">in</span>
parse ((x1 >>= <span class="hljs-keyword">fun</span> y -> x2 >>= <span class="hljs-keyword">fun</span> z -> calcul op y z)::xs) r
| [< >] -> pile
<span class="hljs-keyword">let</span> evaluation chaine =
<span class="hljs-keyword">let</span> resultat = parse <span class="hljs-literal">[]</span> (lexer chaine) <span class="hljs-keyword">in</span>
<span class="hljs-type">List</span>.hd resultat
</code></pre></div>
<p>Un exemple (n’oubliez pas de charger dynlink.cma et camlp4o.cma si vous voulez tester) : </p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span></div><pre><code class="hljs language-ocaml"># evaluation <span class="hljs-string">"2 3 4 * +"</span> ;;
- : <span class="hljs-built_in">int</span> option = <span class="hljs-type">Some</span> <span class="hljs-number">14</span>
</code></pre></div>
<p>Le code initial, qui se contente de la gestion des erreurs par le système d’exceptions d’OCaml, est sensiblement le même, à la différence de la fonction <code>calcul</code> :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-ocaml"><span class="hljs-keyword">let</span> calcul op a b = <span class="hljs-keyword">match</span> op <span class="hljs-keyword">with</span>
| <span class="hljs-string">"+"</span> -> a+b
| <span class="hljs-string">"-"</span> -> a-b
| <span class="hljs-string">"*"</span> -> a*b
| <span class="hljs-string">"/"</span> -> a/b
</code></pre></div>
<p>et de la ligne 21, qui est plus simplement : <code>parse (calcul op x1 x2)::xs r</code> (et la ligne 19 ne contient évidemment pas le constructeur <code>Some</code>).</p>
<p>Cette solution est-elle satisfaisante / pertinente ? En particulier, peut-on dire que le concept de monades est bien appliqué ? Finalement, en OCaml, monades et type option sont donc systématiquement liés ?</p>OCaml et type option : des variables dans un mini interpréteur, message #2209162020-05-18T17:33:28+02:00otini/@otinihttps://zestedesavoir.com/forums/sujet/14089/ocaml-et-type-option-des-variables-dans-un-mini-interpreteur/?page=1#p220916<blockquote>
<p>Je ne suis pas tout à fait d’accord, pour moi on peut écrire
[…]</p>
</blockquote>
<p>C’est vrai, maintenant que tu le dis… <img src="/static/smileys/svg/heureux.svg" alt=":D" class="smiley"> Autant pour moi.</p>OCaml et type option : des variables dans un mini interpréteur, message #2209142020-05-18T17:20:33+02:00gasche/@gaschehttps://zestedesavoir.com/forums/sujet/14089/ocaml-et-type-option-des-variables-dans-un-mini-interpreteur/?page=1#p220914<blockquote>
<p>C’est en effet un peu lourd mais il n’y a pas vraiment de moyen de l’éviter. On pourrait bien sûr utiliser une liste globale au lieu d’un argument de la fonction, mais ça se mariera très mal avec le style fonctionnel d’OCaml.</p>
</blockquote>
<p>Je ne suis pas tout à fait d’accord, pour moi on peut écrire</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-ocaml"><span class="hljs-keyword">let</span> eval env expr =
<span class="hljs-keyword">let</span> <span class="hljs-keyword">rec</span> eval' = <span class="hljs-keyword">function</span>
| <span class="hljs-type">Const</span> n -> <span class="hljs-type">Some</span> n
| <span class="hljs-type">Var</span> v -> find v env
| <span class="hljs-type">Neg</span> e1 -> eval' e1 >>= <span class="hljs-keyword">fun</span> x -> <span class="hljs-type">Some</span> (-x)
| <span class="hljs-type">Add</span> (e1, e2) ->
eval' e1 >>= <span class="hljs-keyword">fun</span> x ->
eval' e2 >>= <span class="hljs-keyword">fun</span> y ->
<span class="hljs-type">Some</span> (x + y)
<span class="hljs-keyword">in</span> eval' expr
</code></pre></div>
<p>et c’est raisonnable et idiomatique. (En fait je nommerais les deux fonctions <code>eval</code>, mais quand on n’a jamais vu ce motif il vaut mieux les distinguer pour la lisibilité.)</p>
<p>Par contre, c’est vrai que cette approche ne marche que quand le paramètre <code>env</code> est constant dans tous les appels récursifs. Si on ajoute une construction pour ajouter des variables au vol, j’aurais tendance à revenir au style initial. On peut éventuellement faire aussi:</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-ocaml"><span class="hljs-keyword">let</span> <span class="hljs-keyword">rec</span> eval env expr =
<span class="hljs-keyword">let</span> eval' e = eval env e <span class="hljs-keyword">in</span>
<span class="hljs-keyword">match</span> expr <span class="hljs-keyword">with</span>
| <span class="hljs-type">Const</span> n -> <span class="hljs-type">Some</span> n
| <span class="hljs-type">Var</span> v -> find v env
| <span class="hljs-type">Neg</span> e1 -> eval' e1 >>= <span class="hljs-keyword">fun</span> x -> <span class="hljs-type">Some</span> (-x)
| <span class="hljs-type">Add</span> (e1, e2) ->
eval' e1 >>= <span class="hljs-keyword">fun</span> x ->
eval' e2 >>= <span class="hljs-keyword">fun</span> y ->
<span class="hljs-type">Some</span> (x + y)
</code></pre></div>
<p>qui est utile quand la <em>plupart</em> des cas utilisent le même environnement, mais certains le modifient.</p>
<p>Ce n’est pas lié mais les versions récentes de OCaml ont un tout petit peu de sucre pour les monades, les "opérateurs de bindings" définissables par l’utilisateur:</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-ocaml"><span class="hljs-keyword">let</span> ( <span class="hljs-keyword">let</span>* ) = <span class="hljs-type">Option</span>.bind
<span class="hljs-keyword">let</span> return v = <span class="hljs-type">Some</span> v
<span class="hljs-keyword">let</span> <span class="hljs-keyword">rec</span> eval env expr =
<span class="hljs-keyword">let</span> eval' e = eval env e <span class="hljs-keyword">in</span>
<span class="hljs-keyword">match</span> expr <span class="hljs-keyword">with</span>
| <span class="hljs-type">Const</span> n -> return n
| <span class="hljs-type">Var</span> v -> <span class="hljs-type">List</span>.assoc_opt v env
| <span class="hljs-type">Neg</span> e1 ->
<span class="hljs-keyword">let</span>* x = eval' e1 <span class="hljs-keyword">in</span>
return (-x)
| <span class="hljs-type">Add</span> (e1, e2) ->
<span class="hljs-keyword">let</span>* x = eval' e1 <span class="hljs-keyword">in</span>
<span class="hljs-keyword">let</span>* y = eval' e2 <span class="hljs-keyword">in</span>
return (x + y)
</code></pre></div>OCaml et type option : des variables dans un mini interpréteur, message #2209122020-05-18T17:17:00+02:00titus/@titushttps://zestedesavoir.com/forums/sujet/14089/ocaml-et-type-option-des-variables-dans-un-mini-interpreteur/?page=1#p220912<p>Merci pour tes réponses précises otini. Je vais donc adopter l’opérateur <code>(>>=)</code> puisqu’il semble être omniprésent lorsqu’on parle de monades !</p>
<blockquote>
<p>Mais si : ton programme est capable d’évaluer les expressions contenant des variables, et il utilise la fonction <code>bind</code> pour cela.</p>
</blockquote>
<p>C’est justement le sens de ma question. Dans le code, sauf erreur de ma part, l’évaluation des variables ne fait pas appel à <code>bind</code>, puisque la ligne concernée de la fonction d’évaluation appelle la fonction <code>find</code>, qui est indépendante de <code>bind</code> :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span></div><pre><code class="hljs language-ocaml">| <span class="hljs-type">Var</span> v -> find v l
</code></pre></div>
<p>Il me semblait être passé à côté de quelque chose, puisque l’énoncé du TP indique :</p>
<blockquote>
<ul>
<li>Commencez par programmer une fonction valeur x l qui va chercher la valeur correspondant à la chaîne x dans la liste de couples l. Vous pouvez réutiliser la fonction find définie précédemment, ou réécrire une fonction explicitement récursive.</li>
<li>Adaptez ensuite eval pour qu’elle sache traiter les variables. Grâce à (»=), trois lignes suffisent !</li>
</ul>
</blockquote>
<p>Je pense saisir (au moins une partie) de l’intérêt de <code>bind</code> qui est la propagation des résultats mais surtout des erreurs. Puisque tu le proposes, je suis preneur d’éléments sur la <em>monade de lecture</em> qui pourrait nous éviter de passer la liste des variables en paramètre à chaque appel <img src="/static/smileys/svg/smile.svg" alt=":)" class="smiley"></p>