Derniers messages sur Zeste de Savoirhttps://zestedesavoir.com/forums/2020-04-15T00:29:49+02:00Les derniers messages parus sur le forum de Zeste de Savoir.[C++] std::unique_ptr<Base> et std::make_unique<Derived> avec appel du constructeur de l'objet dérivé, le tout passé par argument, message #2189702020-04-15T00:29:49+02:00p4radox/@p4radoxhttps://zestedesavoir.com/forums/sujet/13908/c-stdunique_ptrbase-et-stdmake_uniquederived-avec-appel-du-constructeur-de-lobjet-derive-le-tout-passe-par-argument/?page=1#p218970<p>Bonsoir,</p>
<p>Je te remercie de ta réponse, un plaisir que ce soit toi, je suis surpris d’ailleurs lol</p>
<p>J’ai effectivement lu le cours de C++ en instance d’écriture ici même, cette partie en particulier je n’étais donc pas très loin <img src="/static/smileys/langue.png" alt=":P" class="smiley"></p>
<p>En effet, le typage s’opère à la compilation et y pensant c’est vrai que la copie n’est pas compatible avec la sémantique d’entité mais j’ai dû sauter une ou deux ligne à la lecture là je crois :/</p>
<p>Dans mon cas, ce serait un coût de maintenabilité du code si je garde ce modèle qui n’est pas dénué de sens dans ma vision des choses où je vais pouvoir stocker tous les objets dits "lourds" (Textures, Audio, Polices d’écriture, etc…) dans des handlers acceptant des dérivés d’une classe mère à toutes les entités du programme. Sachant que les handlers possèdent des comportements identiques (Allouer l’espace, donner un accès à un asset) je me suis dit que c’était légitime de coller des interfaces à un handler abstrait.</p>
<p>Très bien, content de cette réponse, je vais réfléchir à une solution en prenant en compte ces informations.</p>
<p>Merci monsieur !</p>[C++] std::unique_ptr<Base> et std::make_unique<Derived> avec appel du constructeur de l'objet dérivé, le tout passé par argument, message #2189592020-04-14T20:45:17+02:00gbdivers/@gbdivershttps://zestedesavoir.com/forums/sujet/13908/c-stdunique_ptrbase-et-stdmake_uniquederived-avec-appel-du-constructeur-de-lobjet-derive-le-tout-passe-par-argument/?page=1#p218959<p>C’est le problème classique de la copie avec les classe à sémantique d’entité. Si tu fais une recherche sur le forum, tu devrais trouver des explications plus détaillé (en particulier dans la discussion sur le cours C++).</p>
<p>Pour résumer le problème, quand tu écris :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span></div><pre><code class="hljs language-cpp"><span class="hljs-built_in">std</span>::make_unique<TextureNode>(p_newNode)})
</code></pre></div>
<p>comment sais tu que <code>p_newNode</code> est de type <code>TextureNode</code> et donc que c’est une copie ?</p>
<p>En C++, comme tu as un typage à la compilation, si tu veux faire une copie d’un type polymorphique en écrivant :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span></div><pre><code class="hljs language-cpp">make_unique<???>(object)
</code></pre></div>
<p>il faut connaître le type dynamique de <code>object</code> (ie le type concret de <code>object</code> pendant l’exécution) à la compilation, ce qui n’a pas trop de sens.</p>
<p>Du coup, il faut résoudre dynamiquement le type, par exemple avec un code comme ça :</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-cpp"><span class="hljs-keyword">if</span> (<span class="hljs-string">"object est de type OBJECT1"</span>)
make_unique<OBJECT1>(object)
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-string">"object est de type OBJECT2"</span>)
make_unique<OBJECT2>(object)
etc.
</code></pre></div>
<p>avec "object est de type OBJECT1" qui peut être un <code>dynamic_cast</code> ou une fonction virtuelle <code>type()</code> ou autre.</p>
<p>Une autre solution est d’utiliser le design pattern <code>clone</code> <a href="https://en.wikipedia.org/wiki/Prototype_pattern">https://en.wikipedia.org/wiki/Prototype_pattern</a>. Mais c’est en fait exactement le même principe (résolution dynamique du type), sauf que cela utiliser le mécanisme des fonctions virtuelles plutôt que <code>dynamic_cast</code>.</p>
<p>Dans tous les cas, on a 2 problèmes :</p>
<ul>
<li>surcoût a l’exécution</li>
<li>perte de maintenabilité du code</li>
</ul>
<p>C’est pour cela qu’on dit en général que la copie n’est pas compatible avec la sémantique d’entité.</p>
<p>Pour résoudre ce problème :</p>
<ul>
<li>soit ne pas faire ça et corriger le design</li>
<li>soit accepter le coût des solutions précédentes </li>
</ul>[C++] std::unique_ptr<Base> et std::make_unique<Derived> avec appel du constructeur de l'objet dérivé, le tout passé par argument, message #2189402020-04-14T16:15:47+02:00p4radox/@p4radoxhttps://zestedesavoir.com/forums/sujet/13908/c-stdunique_ptrbase-et-stdmake_uniquederived-avec-appel-du-constructeur-de-lobjet-derive-le-tout-passe-par-argument/?page=1#p218940<p>Bonjour,</p>
<p>Voilà maintenant 3 jours que je parcours le net à la recherche d’une réponse (Francophone et anglophone), même la doc du langage.</p>
<p>Voici le code que je suis en train de tester et ma question qui le succède:</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><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><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-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><string></span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><unordered_map></span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><memory></span></span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BaseNode</span>
{</span>
<span class="hljs-keyword">private</span>:
<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> m_identifier;
<span class="hljs-keyword">protected</span>:
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">()</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-keyword">public</span>:
BaseNode(){}
BaseNode(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_identifier) : m_identifier(p_identifier){}
BaseNode(BaseNode <span class="hljs-keyword">const</span>& rhs){ m_identifier = rhs.getIdentifier(); }
<span class="hljs-keyword">virtual</span> ~BaseNode(){}
<span class="hljs-built_in">std</span>::<span class="hljs-function"><span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& <span class="hljs-title">getIdentifier</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span> </span>{ <span class="hljs-keyword">return</span> m_identifier; }
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setIdentifier</span><span class="hljs-params">(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_identifier)</span> </span>{ m_identifier = p_identifier; }
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NodeHandler</span> :</span> <span class="hljs-keyword">public</span> BaseNode
{
<span class="hljs-keyword">protected</span>:
<span class="hljs-built_in">std</span>::<span class="hljs-built_in">unordered_map</span><<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>, <span class="hljs-built_in">std</span>::<span class="hljs-built_in">unique_ptr</span><BaseNode>> m_handler;
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">()</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">clear</span><span class="hljs-params">()</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-keyword">public</span>:
NodeHandler(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_identifier) : BaseNode(p_identifier) {
m_handler.clear();
}
<span class="hljs-keyword">virtual</span> ~NodeHandler(){}
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">loadNewNode</span><span class="hljs-params">(BaseNode <span class="hljs-keyword">const</span>& p_newNode)</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-function"><span class="hljs-keyword">virtual</span> BaseNode* <span class="hljs-title">getNode</span><span class="hljs-params">(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_identifier)</span> </span>= <span class="hljs-number">0</span>;
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AssetNode</span> :</span> <span class="hljs-keyword">public</span> BaseNode
{
<span class="hljs-keyword">private</span>:
<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> m_filePath;
<span class="hljs-keyword">protected</span>:
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">()</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-keyword">public</span>:
AssetNode(){}
AssetNode(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_identifier, <span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_filePath) : BaseNode(p_identifier), m_filePath(p_filePath) {}
AssetNode(AssetNode <span class="hljs-keyword">const</span>& rhs) : BaseNode(rhs.getIdentifier()), m_filePath(rhs.getFilePath()) {}
<span class="hljs-keyword">virtual</span> ~AssetNode(){}
<span class="hljs-built_in">std</span>::<span class="hljs-function"><span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& <span class="hljs-title">getFilePath</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span> </span>{ <span class="hljs-keyword">return</span> m_filePath; }
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setFilePath</span><span class="hljs-params">(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_filePath)</span> </span>{ m_filePath = p_filePath; }
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TextureNode</span> :</span> <span class="hljs-keyword">public</span> AssetNode
{
<span class="hljs-keyword">private</span>:
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">()</span> override </span>{}
<span class="hljs-keyword">public</span>:
TextureNode(){}
TextureNode(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_identifier, <span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_filePath) : AssetNode(p_identifier, p_filePath) {}
TextureNode(TextureNode <span class="hljs-keyword">const</span>& rhs) : AssetNode(rhs.getIdentifier(), rhs.getFilePath()) {}
~TextureNode() { deleteNode(); }
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TextureHandler</span> :</span> <span class="hljs-keyword">public</span> NodeHandler
{
<span class="hljs-keyword">private</span>:
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">()</span> override </span>{}
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">clear</span><span class="hljs-params">()</span> override </span>{ m_handler.clear(); }
<span class="hljs-keyword">public</span>:
TextureHandler(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_identifier) : NodeHandler(p_identifier) { clear(); }
~TextureHandler() { clear(); }
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">loadNewNode</span><span class="hljs-params">(BaseNode <span class="hljs-keyword">const</span>& p_newNode)</span> override </span>{
m_handler.insert({p_newNode.getIdentifier(), <span class="hljs-built_in">std</span>::make_unique<TextureNode>(p_newNode)});
}
<span class="hljs-function"><span class="hljs-keyword">virtual</span> BaseNode* <span class="hljs-title">getNode</span><span class="hljs-params">(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> <span class="hljs-keyword">const</span>& p_identifier)</span> override </span>{
<span class="hljs-keyword">return</span> (TextureNode*)m_handler[p_identifier].get();
}
};
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{
<span class="hljs-function">TextureHandler <span class="hljs-title">t_handler</span><span class="hljs-params">(<span class="hljs-string">"Texture Handler"</span>)</span></span>;
t_handler.loadNewNode(TextureNode(<span class="hljs-string">"Texture"</span>, <span class="hljs-string">"texture.png"</span>));
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre></div>
<p>En compilant avec <code>g++ testnode.cpp -std=c++17 -Wall -Wextra -pedantic -O2 -o testnode.out</code> j’obtiens la baffe dans la tronche suivante:</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></div><pre><code class="hljs language-text">In file included from /usr/include/c++/8/memory:80,
from testnode.cpp:3:
/usr/include/c++/8/bits/unique_ptr.h: In instantiation of ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = TextureNode; _Args = {const BaseNode&}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<TextureNode, std::default_delete<TextureNode> >]’:
testnode.cpp:86:97: required from here
/usr/include/c++/8/bits/unique_ptr.h:831:30: error: no matching function for call to ‘TextureNode::TextureNode(const BaseNode&)’
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
testnode.cpp:70:9: note: candidate: ‘TextureNode::TextureNode(const TextureNode&)’
TextureNode(TextureNode const& rhs) : AssetNode(rhs.getIdentifier(), rhs.getFilePath()) {}
^~~~~~~~~~~
testnode.cpp:70:9: note: no known conversion for argument 1 from ‘const BaseNode’ to ‘const TextureNode&’
testnode.cpp:69:9: note: candidate: ‘TextureNode::TextureNode(const string&, const string&)’
TextureNode(std::string const& p_identifier, std::string const& p_filePath) : AssetNode(p_identifier, p_filePath) {}
^~~~~~~~~~~
testnode.cpp:69:9: note: candidate expects 2 arguments, 1 provided
testnode.cpp:68:9: note: candidate: ‘TextureNode::TextureNode()’
TextureNode(){}
^~~~~~~~~~~
testnode.cpp:68:9: note: candidate expects 0 arguments, 1 provided
</code></pre></div>
<p>Voici donc ma question: Comment puis-je procéder afin qu’en passant n’importe quel objet dérivé de <code>BaseNode</code> à la fonction <code>TextureHandler::loadNewNode(BaseNode const& p_newNode)</code> il utilise le constructeur de copie de l’objet dérivé et non celui de la classe abstraite <code>BaseNode</code> (Ligne 86) ? Je pense que j’ai dû louper une marche quelque part.
Je ne souhaite pas utiliser un pansement Template, sinon la hiérarchie de ces objets n’aurait aucun sens.</p>
<p>Désolé pour le pavé(César)</p>
<p>Merci d’avance.</p>
<p>EDIT: Le seul moyen que j’ai trouvé pour régler le problème est de déclarer dans chaque handler dérivé de <code>NodeHandler</code> une fonction <code>loadNewNode()</code> et <code>getNode()</code> avec directement le type dérivé en paramètres.
Dans ce cas là, la classe <code>NodeHandler</code> ne fait qu’encapsuler la déclaration du <code>std::unique_ptr</code> et l’appel à la fonction <code>clear()</code> du <code>std::unordered_map<></code> dans son constructeur. Cela casse un peu le rythme de la POO non ?</p> Limitations du polymorphisme à la ML pour une machine à pile, message #1399632017-01-31T18:52:22+01:00dentuk/@dentukhttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139963<p>Les préoccupations de l’utilisateur d’une fonction sont 1) qu’elle soit sûre ; 2) qu’elle soit optimisée. C’est pourquoi il n’est pas gênant d’utiliser <code>Obj.magic</code> lorsque l’on fournit une fonction, si l’on sait par ailleurs que notre fonction reste sûre (il y a une discussion à ce sujet <a href="https://www.reddit.com/r/ocaml/comments/pvcwb/legitimate_uses_for_objmagic/">ici</a>). Selon moi les GADT doivent apporter des garanties supplémentaires à l’utilisateur, sans gêner pour autant la personne qui implémente (Saroupille ici).</p>
<p>L’implémentation ci-dessous me semble être la plus optimisée (récursive terminale) :</p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">type</span> <span class="n">unsafe_instr</span> <span class="o">=</span>
<span class="o">|</span> <span class="nc">UEmpty</span> <span class="o">:</span> <span class="n">unsafe_instr</span>
<span class="o">|</span> <span class="nc">UInt</span> <span class="o">:</span> <span class="kt">int</span> <span class="o">*</span> <span class="n">unsafe_instr</span> <span class="o">-></span> <span class="n">unsafe_instr</span>
<span class="o">|</span> <span class="nc">UCons</span> <span class="o">:</span> <span class="n">unsafe_instr</span> <span class="o">-></span> <span class="n">unsafe_instr</span>
<span class="o">|</span> <span class="nc">UNil</span> <span class="o">:</span> <span class="n">unsafe_instr</span> <span class="o">-></span> <span class="n">unsafe_instr</span>
<span class="k">let</span> <span class="n">unsafe_mk_list</span> <span class="n">l</span> <span class="o">=</span>
<span class="k">let</span> <span class="n">push_ints</span> <span class="n">code</span> <span class="o">=</span>
<span class="nn">List</span><span class="p">.</span><span class="n">fold_left</span> <span class="o">(</span><span class="k">fun</span> <span class="n">top</span> <span class="n">x</span> <span class="o">-></span> <span class="nc">UInt</span><span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">top</span><span class="o">))</span> <span class="n">code</span> <span class="n">l</span>
<span class="k">in</span>
<span class="k">let</span> <span class="n">push_nil</span> <span class="n">code</span> <span class="o">=</span>
<span class="nc">UNil</span> <span class="n">code</span>
<span class="k">in</span>
<span class="k">let</span> <span class="n">cons_all</span> <span class="n">code</span> <span class="o">=</span>
<span class="nn">List</span><span class="p">.</span><span class="n">fold_left</span> <span class="o">(</span><span class="k">fun</span> <span class="n">top</span> <span class="o">_</span> <span class="o">-></span> <span class="nc">UCons</span> <span class="n">top</span><span class="o">)</span> <span class="n">code</span> <span class="n">l</span>
<span class="k">in</span>
<span class="k">fun</span> <span class="n">code</span> <span class="o">-></span> <span class="n">cons_all</span> <span class="o">(</span><span class="n">push_nil</span> <span class="o">(</span><span class="n">push_ints</span> <span class="n">code</span><span class="o">))</span>
</pre></div>
</td></tr></table></div>
<p>Cependant la variante utilisant vos GADTs sera mal typée à cause des valeurs intermédiaires produites, bien que l’on puisse prouver que cette fonction produit toujours comme valeur finale une séquence bien formée typable avec vos GADT. D’où la nécessité d’utiliser <code>Obj.magic</code> si l’on souhaite implémenter cette variante.</p>
<p>Je ne dis pas qu’il faut systématiquement privilégier la version avec <code>Obj.magic</code>, mais, étant donné le titre de ce sujet, j’ai cru que c’était à ce genre de fonctions que pensait Saroupille.</p> Limitations du polymorphisme à la ML pour une machine à pile, message #1399032017-01-31T11:52:33+01:00Eusèbe/@Eus%C3%A8behttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139903<blockquote>
<p>C’est possible mais ça nécessite l’utilisation de <code>Obj.magic</code> </p>
</blockquote>
<p>C’est bien la peine de s’embêter à exprimer des propriétés fortes dans le système de types si c’est pour annuler toutes les garanties avec <code>Obj.magic</code> <img alt=":-P" src="/static/smileys/langue.png"> </p>
<blockquote>
<p>car on aura effectivement des valeurs intermédiaires qui sont non-typables sans types dépendants (leur type dépend de la longueur de la liste). </p>
</blockquote>
<p>Je n’ai pas en tête la solution dont tu parles, donc je ne sais pas exactement de quelles opérations tu as besoin sur tes longueurs de liste, mais encoder le type « liste de longueur n » dans OCaml, ça se fait assez facilement. Il y a aussi un encodage qui permet de faire une concaténation (donc une addition sur les entiers-types).</p>
<blockquote>
<p>Cela peut se justifier pour des raisons de performance par exemple (la récursion d’Eusèbe n’est pas terminale)</p>
</blockquote>
<p>Ouais euh, les performances c’est bien, mais là tu fais un peu mal aux mouches <img alt=":-P" src="/static/smileys/langue.png"> D’autant plus que ce serait pas vraiment compliqué de transformer ça en une récursion terminale ici (quitte à ce que la liste soit retournée, de toute façon je ne suis même pas sûr que je l’empile dans le bon ordre).</p>
<p>Edit : </p>
<p>Pour le fun :</p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">type</span> <span class="o">_</span> <span class="n">op</span> <span class="o">=</span>
<span class="o">|</span> <span class="nc">Empty</span> <span class="o">:</span> <span class="kt">unit</span> <span class="n">op</span>
<span class="o">|</span> <span class="nc">Int</span> <span class="o">:</span> <span class="kt">int</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span> <span class="n">op</span> <span class="o">-></span> <span class="o">(</span><span class="kt">int</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">op</span>
<span class="o">|</span> <span class="nc">Cons</span> <span class="o">:</span> <span class="o">(</span><span class="k">'</span><span class="n">t</span> <span class="kt">list</span> <span class="o">*</span> <span class="o">(</span><span class="k">'</span><span class="n">t</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">))</span> <span class="n">op</span> <span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">t</span> <span class="kt">list</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">op</span>
<span class="o">|</span> <span class="nc">Nil</span> <span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="n">op</span> <span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">b</span> <span class="kt">list</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">op</span>
<span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="nc">Cons</span> <span class="o">(</span><span class="nc">Cons</span> <span class="o">(</span><span class="nc">Nil</span> <span class="o">(</span><span class="nc">Int</span> <span class="o">(</span><span class="mi">5</span><span class="o">,</span><span class="nc">Int</span> <span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="nc">Empty</span><span class="o">)))))</span>
<span class="k">let</span> <span class="n">start</span> <span class="n">f</span> <span class="o">=</span> <span class="n">f</span> <span class="nc">Empty</span>
<span class="k">let</span> <span class="n">finish</span> <span class="n">s</span> <span class="o">=</span> <span class="n">s</span>
<span class="k">let</span> <span class="kt">int</span> <span class="n">stack</span> <span class="n">x</span> <span class="n">k</span> <span class="o">=</span>
<span class="n">k</span> <span class="o">@@</span> <span class="nc">Int</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">stack</span><span class="o">)</span>
<span class="k">let</span> <span class="n">cons</span> <span class="n">stack</span> <span class="n">k</span> <span class="o">=</span>
<span class="n">k</span> <span class="o">@@</span> <span class="nc">Cons</span> <span class="n">stack</span>
<span class="k">let</span> <span class="n">nil</span> <span class="n">stack</span> <span class="n">k</span> <span class="o">=</span>
<span class="n">k</span> <span class="o">@@</span> <span class="nc">Nil</span> <span class="n">stack</span>
<span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="n">start</span>
<span class="kt">int</span> <span class="mi">3</span>
<span class="kt">int</span> <span class="mi">2</span>
<span class="n">nil</span>
<span class="n">cons</span>
<span class="n">finish</span>
<span class="c">(* val s : (int list * (int * unit)) op = Cons (Nil (Int (2, Int (3, Empty)))) *)</span>
</pre></div>
</td></tr></table></div>
<p>Bon ici, il s’agit juste de construire une liste bien typée, donc c’est moins fun que l’exemple habituel qui embarque un langage à pile dans OCaml (avec des opérations qui peuvent dépiler des choses, par exemple <code>add</code>).</p> Limitations du polymorphisme à la ML pour une machine à pile, message #1398752017-01-31T02:31:35+01:00Saroupille/@Saroupillehttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139875<p>Je ne pense pas qu’il y ait besoin des types dépendants ici car il n’y a pas besoin de connaître la taille de la liste grâce au constructeur <code>Cons</code>.</p> Limitations du polymorphisme à la ML pour une machine à pile, message #1398732017-01-31T00:55:24+01:00dentuk/@dentukhttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139873<p>Peut-être pensais-tu à une version à base de deux <code>List.fold_left</code> qui ferait du <code>"n Cons"(Nil("n Int"(s)))</code> ? C’est possible mais ça nécessite l’utilisation de <code>Obj.magic</code> car on aura effectivement des valeurs intermédiaires qui sont non-typables sans types dépendants (leur type dépend de la longueur de la liste). Cela peut se justifier pour des raisons de performance par exemple (la récursion d’Eusèbe n’est pas terminale), et dans la mesure où l’on sait que la valeur finale aura bien le type qu’on lui assigne (noter que le type de la valeur finale, lui, ne dépend pas de la longueur de la liste).</p> Limitations du polymorphisme à la ML pour une machine à pile, message #1398452017-01-30T15:55:42+01:00Saroupille/@Saroupillehttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139845<p>Ok, c’est plus ou moins la solution à laquelle j’étais arrivée. Après je rejoins tes remarques sur ce que je propose. Mais j’avoue ne pas avoir pris trop de recul sur le code que j’ai écrit plus haut. Au début j’ai appelé ça <code>succ</code> mais ensuite j’ai renommé ça en <code>stack</code> car c’est plus intuitif.</p> Limitations du polymorphisme à la ML pour une machine à pile, message #1398432017-01-30T15:39:57+01:00Eusèbe/@Eus%C3%A8behttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139843<p>Le type <code>instr</code> que tu proposes est inutilement compliqué : le type <code>stack</code> est essentiellement un type produit mais avec un wrapper autour, je ne sais pas d’où sort le type <code>succ</code>, etc. Le type que je propose est le même, mais syntaxiquement plus simple, et effectivement restreint aux listes d’entiers. Voilà une version qui fonctionne avec n’importe quelles listes. C’est encore une fois plus simple que ce que tu as écrit, mais moralement c’est exactement pareil. J’ai utilisé un record pour avoir un push polymorphe, mais je pense que tant qu’à utiliser des gadt, c’est probablement plus pratique d’avoir un <code>Const</code> dans le type des opérations comme je le propose plus haut. </p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">type</span> <span class="o">_</span> <span class="n">op</span> <span class="o">=</span>
<span class="o">|</span> <span class="nc">Empty</span> <span class="o">:</span> <span class="kt">unit</span> <span class="n">op</span>
<span class="o">|</span> <span class="nc">Int</span> <span class="o">:</span> <span class="kt">int</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span> <span class="n">op</span> <span class="o">-></span> <span class="o">(</span><span class="kt">int</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">op</span>
<span class="o">|</span> <span class="nc">Cons</span> <span class="o">:</span> <span class="o">(</span><span class="k">'</span><span class="n">t</span> <span class="kt">list</span> <span class="o">*</span> <span class="o">(</span><span class="k">'</span><span class="n">t</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">))</span> <span class="n">op</span> <span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">t</span> <span class="kt">list</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">op</span>
<span class="o">|</span> <span class="nc">Nil</span> <span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="n">op</span> <span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">b</span> <span class="kt">list</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">op</span>
<span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="nc">Cons</span> <span class="o">(</span><span class="nc">Cons</span> <span class="o">(</span><span class="nc">Nil</span> <span class="o">(</span><span class="nc">Int</span> <span class="o">(</span><span class="mi">5</span><span class="o">,</span><span class="nc">Int</span> <span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="nc">Empty</span><span class="o">)))))</span>
<span class="k">let</span> <span class="k">rec</span> <span class="n">mk_int_list</span> <span class="o">:</span> <span class="k">type</span> <span class="n">a</span><span class="o">.</span> <span class="n">a</span> <span class="n">op</span> <span class="o">-></span> <span class="o">_</span> <span class="o">-></span> <span class="o">(</span><span class="kt">int</span> <span class="kt">list</span> <span class="o">*</span> <span class="n">a</span><span class="o">)</span> <span class="n">op</span> <span class="o">=</span>
<span class="k">fun</span> <span class="n">s</span> <span class="n">li</span> <span class="o">-></span>
<span class="k">match</span> <span class="n">li</span> <span class="k">with</span>
<span class="o">|</span> <span class="bp">[]</span> <span class="o">-></span> <span class="nc">Nil</span> <span class="n">s</span>
<span class="o">|</span> <span class="n">x</span> <span class="o">::</span> <span class="n">xs</span> <span class="o">-></span>
<span class="nc">Cons</span> <span class="o">(</span><span class="n">mk_int_list</span> <span class="o">(</span><span class="nc">Int</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">s</span><span class="o">))</span> <span class="n">xs</span><span class="o">)</span>
<span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="n">mk_int_list</span> <span class="nc">Empty</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="mi">4</span><span class="o">]</span>
<span class="k">type</span> <span class="k">'</span><span class="n">a</span> <span class="n">push</span> <span class="o">=</span> <span class="o">{</span> <span class="n">push</span> <span class="o">:</span> <span class="k">'</span><span class="n">t</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">t</span> <span class="n">op</span> <span class="o">-></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">t</span><span class="o">)</span> <span class="n">op</span> <span class="o">}</span>
<span class="k">let</span> <span class="n">int_push</span> <span class="o">=</span> <span class="o">{</span> <span class="n">push</span> <span class="o">=</span> <span class="k">fun</span> <span class="n">x</span> <span class="n">s</span> <span class="o">-></span> <span class="nc">Int</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">s</span><span class="o">)</span> <span class="o">}</span>
<span class="k">let</span> <span class="k">rec</span> <span class="n">mk_list</span> <span class="o">:</span> <span class="k">type</span> <span class="n">a</span><span class="o">.</span> <span class="o">_</span> <span class="o">-></span> <span class="n">a</span> <span class="n">op</span> <span class="o">-></span> <span class="o">_</span> <span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">b</span> <span class="kt">list</span> <span class="o">*</span> <span class="n">a</span><span class="o">)</span> <span class="n">op</span> <span class="o">=</span>
<span class="k">fun</span> <span class="n">push</span> <span class="n">s</span> <span class="n">li</span> <span class="o">-></span>
<span class="k">match</span> <span class="n">li</span> <span class="k">with</span>
<span class="o">|</span> <span class="bp">[]</span> <span class="o">-></span> <span class="nc">Nil</span> <span class="n">s</span>
<span class="o">|</span> <span class="n">x</span> <span class="o">::</span> <span class="n">xs</span> <span class="o">-></span>
<span class="nc">Cons</span> <span class="o">(</span><span class="n">mk_list</span> <span class="n">push</span> <span class="o">(</span><span class="n">push</span><span class="o">.</span><span class="n">push</span> <span class="n">x</span> <span class="n">s</span><span class="o">)</span> <span class="n">xs</span><span class="o">)</span>
<span class="k">let</span> <span class="n">ss</span> <span class="o">=</span> <span class="n">mk_list</span> <span class="n">int_push</span> <span class="nc">Empty</span> <span class="o">[</span><span class="mi">5</span><span class="o">;</span> <span class="mi">6</span><span class="o">;</span> <span class="mi">7</span><span class="o">;</span> <span class="mi">8</span><span class="o">]</span>
<span class="c">(* val ss : (int list * unit) op =</span>
<span class="c"> Cons (Cons (Cons (Cons (Nil (Int (8, Int (7, Int (6, Int (5, Empty))))))))) *)</span>
</pre></div>
</td></tr></table></div> Limitations du polymorphisme à la ML pour une machine à pile, message #1398422017-01-30T15:30:04+01:00Saroupille/@Saroupillehttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139842<p>Ok, ça fonctionne car tu changes les types que je propose dès le départ. Pourquoi pas, c’est en effet plus simple que ce que j’avais en tête.</p>
<p>Je regarderai ça à tête reposée, mais cette solution ne fonctionne pas avec le type instr que je propose, en tout cas dans le cas polymorphe.</p> Limitations du polymorphisme à la ML pour une machine à pile, message #1398382017-01-30T14:51:23+01:00Eusèbe/@Eus%C3%A8behttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139838<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">type</span> <span class="o">_</span> <span class="n">op</span> <span class="o">=</span>
<span class="o">|</span> <span class="nc">Empty</span> <span class="o">:</span> <span class="kt">unit</span> <span class="n">op</span>
<span class="o">|</span> <span class="nc">Int</span> <span class="o">:</span> <span class="kt">int</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span> <span class="n">op</span> <span class="o">-></span> <span class="o">(</span><span class="kt">int</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">op</span>
<span class="o">|</span> <span class="nc">Cons</span> <span class="o">:</span> <span class="o">(</span><span class="kt">int</span> <span class="kt">list</span> <span class="o">*</span> <span class="o">(</span><span class="kt">int</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">))</span> <span class="n">op</span> <span class="o">-></span> <span class="o">(</span><span class="kt">int</span> <span class="kt">list</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">op</span>
<span class="o">|</span> <span class="nc">Nil</span> <span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="n">op</span> <span class="o">-></span> <span class="o">(</span><span class="kt">int</span> <span class="kt">list</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">op</span>
<span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="nc">Cons</span> <span class="o">(</span><span class="nc">Cons</span> <span class="o">(</span><span class="nc">Nil</span> <span class="o">(</span><span class="nc">Int</span> <span class="o">(</span><span class="mi">5</span><span class="o">,</span><span class="nc">Int</span> <span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="nc">Empty</span><span class="o">)))))</span>
<span class="k">let</span> <span class="k">rec</span> <span class="n">mk_list</span> <span class="o">:</span> <span class="k">type</span> <span class="n">a</span><span class="o">.</span> <span class="n">a</span> <span class="n">op</span> <span class="o">-></span> <span class="o">_</span> <span class="o">-></span> <span class="o">(</span><span class="kt">int</span> <span class="kt">list</span> <span class="o">*</span> <span class="n">a</span><span class="o">)</span> <span class="n">op</span> <span class="o">=</span>
<span class="k">fun</span> <span class="n">s</span> <span class="n">li</span> <span class="o">-></span>
<span class="k">match</span> <span class="n">li</span> <span class="k">with</span>
<span class="o">|</span> <span class="bp">[]</span> <span class="o">-></span> <span class="nc">Nil</span> <span class="n">s</span>
<span class="o">|</span> <span class="n">x</span> <span class="o">::</span> <span class="n">xs</span> <span class="o">-></span>
<span class="nc">Cons</span> <span class="o">(</span><span class="n">mk_list</span> <span class="o">(</span><span class="nc">Int</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">s</span><span class="o">))</span> <span class="n">xs</span><span class="o">)</span>
<span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="n">mk_list</span> <span class="nc">Empty</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="mi">4</span><span class="o">]</span>
<span class="c">(* val s : (int list * unit) op =</span>
<span class="c"> Cons (Cons (Cons (Cons (Nil (Int (4, Int (3, Int (2, Int (1, Empty))))))))) *)</span>
</pre></div>
</td></tr></table></div>
<p>On pourrait aussi faire une fonction générique, mais ça demanderait de changer le constructeur <code>Int</code> vers un <code>Const : 'a * 'b op -> ('a * 'b) op</code>, et on utilise <code>Const</code> dans <code>mk_list</code>. </p> Limitations du polymorphisme à la ML pour une machine à pile, message #1398372017-01-30T14:12:06+01:00Ksass`Peuk/@Ksass%60Peukhttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139837<p>Lu’!</p>
<p>Totalement HS : ce serait pas mal de mettre tes tags dans le formulaire correspondant aux tags du sujet plutôt que dans le titre du sujet.</p> Limitations du polymorphisme à la ML pour une machine à pile, message #1398352017-01-30T14:00:52+01:00Saroupille/@Saroupillehttps://zestedesavoir.com/forums/sujet/7888/limitations-du-polymorphisme-a-la-ml-pour-une-machine-a-pile/?page=1#p139835<p>Bonjour,</p>
<p>Dans le cadre de mon travail, je dois encoder une machine à pile. Cette dernière gère une pile que l’on peut manipuler grâce à des commandes. Pour l’exemple que je vais montrer, on va considérer que notre machine ne peut contenir que des <em>entiers</em> et des <em>listes</em> d’entiers que l’on peut manipuler grâce à 4 commandes :</p>
<ul>
<li>Empty : créer la pile vide</li>
<li>Int(n) : empile l’entier n sur la pile</li>
<li>Nil : empile la liste vide</li>
<li>Cons : dépile une liste <code>l</code>, dépile un entier <code>n</code> et empile une nouvelle liste <code>n::l</code> </li>
</ul>
<p>Ainsi le programme suivant :</p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><div class="codehilite"><pre><span></span>Empty
Int(2)
Int(5)
Nil
Cons
Cons
</pre></div>
</td></tr></table></div>
<p>contient sur le sommet de la pile la liste <code>[2;5]</code>. Par contre le programme suivant :</p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><div class="codehilite"><pre><span></span>Empty
Int(2)
Nil
Cons
Int(5)
Cons
</pre></div>
</td></tr></table></div>
<p>n’est pas un programme valide. Passons au monde de la programmation, et pour ce cas d’étude on va prendre le langage OCaml. Ce qui m’intéresse ici c’est juste le type des instructions (Empty, Nil, …), pas comment on éxécute le programme. Une première façon de représenter les types est la suivante :</p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">type</span> <span class="n">instr</span> <span class="o">=</span>
<span class="o">|</span> <span class="nc">Empty</span>
<span class="o">|</span> <span class="nc">Int</span> <span class="k">of</span> <span class="kt">int</span>
<span class="o">|</span> <span class="nc">Nil</span>
<span class="o">|</span> <span class="nc">Cons</span>
<span class="k">type</span> <span class="n">program</span> <span class="o">=</span> <span class="n">instr</span> <span class="kt">list</span>
</pre></div>
</td></tr></table></div>
<p>Avec cette représentation, on peut écrire notre premier programme, et ce n’est pas très compliqué de créer une fonction qui évalue ce programme. Cependant, on peut aussi écrire le second premier programme avec ce format, et cette fois l’évaluation dudit programme va planter.</p>
<p>On peut se poser la question cependant, si on ne pourrait pas <strong>statiquement</strong> détecter que le second programme est incorrect. En fait si on peut, et pour cela on va utiliser les GADTs. Si vous ne savez pas ce que c’est, je vous invite à aller regarder <a href="https://en.wikipedia.org/wiki/Generalized_algebraic_data_type">ce lien</a>.</p>
<p>On va donc en utilisant les GADTs encoder ce qu’il y a sur notre pile. Pour cela on se donne deux nouveaux types :</p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">type</span> <span class="n">empty</span>
<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">stack</span>
</pre></div>
</td></tr></table></div>
<p><code>empty</code> correspond au type de la pile vide.
<code>('a, 'b) stack</code>corrrespond au type de la pile qui contient à son sommet un objet de type ’a et le reste de la pile est ’b.</p>
<p>Ainsi la pile vide correspond à <code>empty</code> , la pile qui contient à son sommet les entiers 2 et 5 : <code>(int, (int, 'b) stack) stack</code>. Deux remarques sur ce type :</p>
<ul>
<li>la pile qui contient 2 et 5 est indistinguable de la pile qui contient 3 et 4 par exemple. Mais ici c’est attendu car on s’intéresse qu’au type des objets pour savoir si un programme est valide.</li>
<li>le type est polymorphe en <code>'b</code> ce qui veut dire que l’on ne sait rien sur ce qu’il y a ensuite</li>
</ul>
<p>Pour une raison obscure (si quelqu’un veut bien m’expliquer je suis preneur), il faut rajouter un constructeur à succ pour que la suite soit bien typée : </p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">type</span> <span class="n">empty</span>
<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">stack</span> <span class="o">=</span> <span class="nc">Wtf</span>
</pre></div>
</td></tr></table></div>
<p>Maintenant on se donne le type des instructions : </p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">type</span> <span class="k">'</span><span class="n">a</span> <span class="n">instr</span> <span class="o">=</span>
<span class="o">|</span> <span class="nc">Empty</span> <span class="o">:</span> <span class="n">empty</span> <span class="n">instr</span>
<span class="o">|</span> <span class="nc">Int</span> <span class="o">:</span> <span class="kt">int</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span> <span class="n">instr</span> <span class="o">-></span> <span class="o">((</span><span class="kt">int</span><span class="o">,</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">stack</span><span class="o">)</span> <span class="n">instr</span>
<span class="o">|</span> <span class="nc">Cons</span> <span class="o">:</span> <span class="o">(</span><span class="k">'</span><span class="n">b</span> <span class="kt">list</span><span class="o">,</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">stack</span><span class="o">)</span> <span class="n">stack</span> <span class="n">instr</span> <span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">b</span> <span class="kt">list</span><span class="o">,</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">stack</span> <span class="n">instr</span>
<span class="o">|</span> <span class="nc">Nil</span> <span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="n">instr</span> <span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">b</span> <span class="kt">list</span><span class="o">,</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">stack</span> <span class="n">instr</span>
</pre></div>
</td></tr></table></div>
<p>On note que le type <code>instr</code> a maintenant un paramètre polymorphe, le type de notre pile. De plus, tous les constructeurs prennent un paramètre : la pile qui a été construite précédement. En un certain sens, le type <code>'a instr</code>est une généralisation du type <code>'a list</code>. Par exemple pour <code>Cons</code> ce dernier mange une pile qui contient à son sommet une liste dont les éléments sont de type <code>'b</code> et un élément de type <code>'b</code> et ressort une nouvelle pile qui contient cette fois seulement une liste de type <code>'b</code>. </p>
<p>Maintenant, je peux encoder mon premier programme comme :</p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">let</span> <span class="o">_</span> <span class="o">=</span> <span class="nc">Cons</span><span class="o">(</span><span class="nc">Cons</span><span class="o">(</span><span class="nc">Nil</span><span class="o">(</span><span class="nc">Int</span><span class="o">(</span><span class="mi">5</span><span class="o">,</span><span class="nc">Int</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="nc">Empty</span><span class="o">)))))</span>
</pre></div>
</td></tr></table></div>
<p>Par contre, si j’essaye de faire la même chose pour le second programme : </p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">let</span> <span class="o">_</span> <span class="o">=</span> <span class="nc">Cons</span><span class="o">(</span><span class="nc">Int</span><span class="o">(</span><span class="mi">5</span><span class="o">,</span><span class="nc">Cons</span><span class="o">(</span><span class="nc">Nil</span><span class="o">(</span><span class="nc">Int</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="nc">Empty</span><span class="o">)))))</span>
</pre></div>
</td></tr></table></div>
<p>OCaml nous sort une erreur de type. On a donc gagné !</p>
<p>Well…</p>
<p>Essayons de se faire une petite fonction : <code>mk_list</code>. Cette dernière prendrait une liste d’entier OCaml et construirait un programme qui contiendrait les instructions pour créer cette pile. Le prototype de notre fonction serait le suivant :</p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">'</span><span class="n">a</span> <span class="n">instr</span> <span class="o">-></span> <span class="kt">int</span> <span class="kt">list</span> <span class="o">-></span> <span class="o">(</span><span class="kt">int</span> <span class="kt">list</span><span class="o">,</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">succ</span> <span class="n">instr</span>
</pre></div>
</td></tr></table></div>
<p>Le premier paramètre vient du fait que notre programme est censé fonctionner sur toutes les piles. Vous remarquerez que dans les constructeurs de <code>Nil</code> et <code>Cons</code> je n’ai pas précisé le type des listes. En effet, on pourrait imaginer qu’ensuite notre machine manipule aussi des listes de <code>string</code> par exemple. Donc on pourrait aussi vouloir créer une fonction <code>mk_list</code> de type</p>
<div><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">'</span><span class="n">a</span> <span class="n">instr</span> <span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">a</span> <span class="n">instr</span> <span class="o">-></span> <span class="k">'</span><span class="n">b</span> <span class="o">-></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">succ</span> <span class="n">instr</span><span class="o">)</span> <span class="o">-></span> <span class="o">(</span><span class="k">'</span><span class="n">b</span> <span class="kt">list</span><span class="o">,</span> <span class="k">'</span><span class="n">a</span><span class="o">)</span> <span class="n">succ</span> <span class="n">instr</span>
</pre></div>
</td></tr></table></div>
<p>Je vous invite à essayer 5mn de programmer ces prototypes, mais n’essayez pas trop longtemps. Je soupçonne très fortement que ce ne soit pas possible d’implémenter ces fonctions avec ces prototypes. </p>
<p>Si vous avez des idées pour implémenter <code>mk_list</code> (quitte à modifier le prototype) je suis preneur. </p>
<p>Je vous souhaite une bonne journée <img alt=";)" src="/static/smileys/clin.png"></p>