https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112018-11-17T10:56:36ZRuby Issue Tracking SystemRuby master - Feature #15302: Proc#with and Proc#by, for partial function application and curryinghttps://redmine.ruby-lang.org/issues/15302?journal_id=749042018-11-17T10:56:36Zshevegen (Robert A. Heiler)shevegen@gmail.com
<ul></ul><p>I am not sure if the API seems ok. I am also not sure if matz<br>
wants to have <code>Symbol</code>s have methods such as <code>.with()</code>. For example,<br>
to me personally it is not entirely clear why "with 2" would<br>
be equal to "n * 2" as such.</p>
<p>I am also not sure about the use case - it has not been<br>
mentioned in this issue as far as I can see.</p>
<p>However had, perhaps we should wait a bit on the upcoming<br>
developer meeting this year anyway, because there have been<br>
other proposed changes that are somewhat related to the issue<br>
of how much class <code>Symbol</code> should be able to do - e. g. see<br>
what Victor Shepelev suggested, linked in to<br>
<a href="https://bugs.ruby-lang.org/issues/15229" class="external">https://bugs.ruby-lang.org/issues/15229</a> for <code>Symbol#call</code>.</p>
<p>Then we also know matz' opinion about class <code>Symbol</code> in<br>
regards to any possible changes to it.</p> Ruby master - Feature #15302: Proc#with and Proc#by, for partial function application and curryinghttps://redmine.ruby-lang.org/issues/15302?journal_id=749052018-11-17T16:54:36ZRichOrElse (Ritchie Buitre)
<ul></ul><p>shevegen (Robert A. Heiler) wrote:</p>
<blockquote>
<p>I am not sure if the API seems ok. I am also not sure if matz<br>
wants to have Symbols have methods such as .with(). For example,<br>
to me personally it is not entirely clear why "with 2" would<br>
be equal to "n * 2" as such.</p>
</blockquote>
<p>Thank you for taking the time to review my proposal and for the suggestions.<br>
To illustrate more clearly how <strong><code>Symbol#with</code></strong> works, here's another example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="no">DateTime</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">2018</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="no">DateTime</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">2018</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">30</span><span class="p">)].</span><span class="nf">map</span> <span class="o">&</span><span class="ss">:strftime</span><span class="p">.</span><span class="nf">with</span><span class="p">(</span><span class="s2">"%m/%d/%Y"</span><span class="p">)</span>
</code></pre>
<p>Which is the same as the following:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="no">DateTime</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">2018</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="no">DateTime</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">2018</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">30</span><span class="p">)].</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">d</span><span class="o">|</span> <span class="n">d</span><span class="p">.</span><span class="nf">strftime</span><span class="p">(</span><span class="s2">"%m/%d/%Y"</span><span class="p">)</span> <span class="p">}</span>
</code></pre>
<p>Although <a class="issue tracker-5 status-5 priority-4 priority-default closed" title="Misc: DevelopersMeeting20181122Japan (Closed)" href="https://redmine.ruby-lang.org/issues/15229">#15229</a> <strong><code>Symbol#call</code></strong> is shorter than the functional equivalent proposal <code>Symbol#with</code>,<br>
the later's interface is consistent with <strong><code>Proc#with</code></strong> and <strong><code>Method#with</code></strong> where, as you are already aware, have their method <strong><code>call</code></strong> already taken.</p>
<p>shevegen (Robert A. Heiler) wrote:</p>
<blockquote>
<p>I am also not sure about the use case - it has not been<br>
mentioned in this issue as far as I can see.</p>
</blockquote>
<p>Here's a use case for <em>filling optional arguments</em>.<br>
Given a method named <strong><code>greet</code></strong>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">greeting</span> <span class="o">=</span> <span class="s1">'hello'</span><span class="p">)</span>
<span class="nb">p</span> <span class="s2">"</span><span class="si">#{</span><span class="n">greeting</span><span class="p">.</span><span class="nf">capitalize</span><span class="si">}</span><span class="s2">! </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="n">greet</span> <span class="s1">'bob'</span> <span class="c1"># => "Hello! bob"</span>
</code></pre>
<p>We can reuse the same method by pre-filling the last argument like so:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">Spanish</span>
<span class="no">GREETINGS</span> <span class="o">=</span> <span class="nb">method</span><span class="p">(</span><span class="ss">:greet</span><span class="p">).</span><span class="nf">with</span><span class="p">(</span><span class="s1">'hola'</span><span class="p">)</span> <span class="c1"># Using Method#call would invoke the method instead of returning a Proc.</span>
<span class="k">end</span>
<span class="no">Spanish</span><span class="o">::</span><span class="no">GREETINGS</span><span class="p">[</span><span class="s1">'Roberto'</span><span class="p">]</span> <span class="c1"># => "Hola! Roberto"</span>
</code></pre> Ruby master - Feature #15302: Proc#with and Proc#by, for partial function application and curryinghttps://redmine.ruby-lang.org/issues/15302?journal_id=750952018-11-22T22:39:45Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>This kind of partial evaluation is an interesting idea, but as a non-native speaker, I wonder those words do not cause confusion which works which way? At least I was confused.</p>
<p>Matz.</p> Ruby master - Feature #15302: Proc#with and Proc#by, for partial function application and curryinghttps://redmine.ruby-lang.org/issues/15302?journal_id=751062018-11-23T10:16:51ZRichOrElse (Ritchie Buitre)
<ul></ul><p>matz (Yukihiro Matsumoto) wrote:</p>
<blockquote>
<p>I wonder those words do not cause confusion which works which way? At least I was confused.</p>
</blockquote>
<p>I agree with your assessment Matz. Both 'with' and 'by' are such flexible words, they're the first words that came to my mind. Unfortunately they are also too flexible, making them vague.</p>
<a name="Descriptive-Names"></a>
<h2 >Descriptive Names<a href="#Descriptive-Names" class="wiki-anchor">¶</a></h2>
<p>Until the community decides on more useful aliases, for now picking descriptive method names such as 'partial' and 'targets' is less confusing.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Proc</span>
<span class="k">def</span> <span class="nf">partial</span><span class="p">(</span><span class="o">*</span><span class="n">tail</span><span class="p">,</span> <span class="o">&</span><span class="n">blk</span><span class="p">)</span>
<span class="nb">proc</span> <span class="p">{</span> <span class="o">|*</span><span class="n">head</span><span class="o">|</span> <span class="n">call</span><span class="p">(</span><span class="o">*</span><span class="n">head</span><span class="p">,</span> <span class="o">*</span><span class="n">tail</span><span class="p">,</span> <span class="o">&</span><span class="n">blk</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">targets</span><span class="p">(</span><span class="o">*</span><span class="n">head</span><span class="p">)</span>
<span class="n">curry</span><span class="p">(</span><span class="n">head</span><span class="p">.</span><span class="nf">size</span><span class="p">.</span><span class="nf">next</span><span class="p">)[</span><span class="o">*</span><span class="n">head</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<a name="Alternative-Prepositions"></a>
<h2 >Alternative Prepositions<a href="#Alternative-Prepositions" class="wiki-anchor">¶</a></h2>
<p>Even though I am partial to (<em>pun intended</em>) the '<em>with</em>' interface, I ruminated on finding alternative words. So far I've stumbled upon these prepositions which looks promising.</p>
<p><strong>Proc#in</strong> for implicit currying.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">multiply</span> <span class="o">=</span> <span class="o">-></span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="p">{</span> <span class="n">x</span> <span class="o">*</span> <span class="n">y</span> <span class="p">}</span>
<span class="n">double</span> <span class="o">=</span> <span class="n">multiply</span><span class="p">.</span><span class="nf">in</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># => proc { |n| multiply.(2, n) }</span>
</code></pre>
<p><strong>Proc#on</strong> for partial evaluation.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">divide</span> <span class="o">=</span> <span class="o">-></span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="p">{</span> <span class="n">x</span> <span class="o">/</span> <span class="n">y</span> <span class="p">}</span>
<span class="n">half</span> <span class="o">=</span> <span class="n">divide</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># => proc { |n| divide.(n, 2) }</span>
</code></pre>
<p>I like the pairing of '<em>in</em>' with '<em>on</em>'. Aside from being only 2 characters long, they allow to mentally map the arguments placement.</p>
<p>General information are placed first using '<em>in</em>'.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">to_s</span> <span class="o">=</span> <span class="ss">:to_s</span><span class="p">.</span><span class="nf">proc</span> <span class="c1"># => proc {|x, *options| x.to_s(*options) }</span>
<span class="n">ten_to_base</span> <span class="o">=</span> <span class="nb">to_s</span><span class="p">.</span><span class="nf">in</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="c1"># => proc {|base| to_s.(10, base) }</span>
<span class="n">five_to_base</span> <span class="o">=</span> <span class="nb">to_s</span><span class="p">.</span><span class="nf">in</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="c1"># => proc {|base| to_s.(5, base) }</span>
</code></pre>
<p>Specific or optional details are placed last using '<em>on</em>'.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">to_binary</span> <span class="o">=</span> <span class="nb">to_s</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># => proc { |n| to_s.(n, 2) }</span>
<span class="n">to_hexadecimal</span> <span class="o">=</span> <span class="nb">to_s</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span> <span class="c1"># => proc { |n| to_s.(n, 16) }</span>
</code></pre>
<p>On the downside, in some context, the word 'on' is less natural sounding to an English speaker compared to the more flexible word '<em>with</em>'.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">method</span><span class="p">(</span><span class="ss">:greet</span><span class="p">).</span><span class="nf">on</span><span class="p">(</span><span class="s2">"Kon'nichiwa"</span><span class="p">)</span>
</code></pre>
<p>On the upside the word 'in' is less redundant and won't be confused with the '<em>_by</em>' idioms.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">find_person_by</span> <span class="o">=</span> <span class="ss">:find_by</span><span class="p">.</span><span class="nf">in</span><span class="p">(</span><span class="no">Person</span><span class="p">)</span> <span class="c1"># => proc {|*criteria| Person.find_by(*criteria) }</span>
</code></pre>