Gray Soft / Higher-Order Ruby / Infinite Streams
tag:graysoftinc.com,2014-03-20:/posts/9
2014-03-28T20:16:10Z
James Edward Gray II
The 4th Comment on "Infinite Streams"
tag:graysoftinc.com,2007-11-15:/comments/139
2014-03-28T20:16:10Z
> One other point, even less important: the name of the method `show` is a bit curious. It takes a reader (ok, me!) some time to understand the method before he realizes that the intent is to destroy what is read.
Yeah, I don't like that name e...
<blockquote>
<p>One other point, even less important: the name of the method <code>show</code> is a bit curious. It takes a reader (ok, me!) some time to understand the method before he realizes that the intent is to destroy what is read.</p>
</blockquote>
<p>Yeah, I don't like that name either. I most likely used it because it was used in the book and I wanted to keep the code similar. I agree that it could be better though.</p>
James Edward Gray II
The 3rd Comment on "Infinite Streams"
tag:graysoftinc.com,2007-11-15:/comments/138
2014-03-28T20:15:09Z
It works the same because the `tail()` method will return a non-Proc object, what you get from the promise, normally. The rewrite causes the promise to be delivered at the wrong time though, which may cause problems if the promise code is time se...
<p>It works the same because the <code>tail()</code> method will return a non-Proc object, what you get from the promise, normally. The rewrite causes the promise to be delivered at the wrong time though, which may cause problems if the promise code is time sensitive or in other similar scenarios.</p>
James Edward Gray II
The 2nd Comment on "Infinite Streams"
tag:graysoftinc.com,2007-11-15:/comments/137
2014-03-28T20:15:09Z
I see: the line
```ruby
next_stream.instance_eval { [@head, @tail] }
```
does not execute the tail promise, it just retrieves the variable(s).
While the line
```ruby
[next_stream.head, next_stream.tail]
```
would se...
<p>I see: the line </p>
<div class="highlight highlight-ruby"><pre><span class="n">next_stream</span><span class="o">.</span><span class="n">instance_eval</span> <span class="p">{</span> <span class="o">[</span><span class="vi">@head</span><span class="p">,</span> <span class="vi">@tail</span><span class="o">]</span> <span class="p">}</span>
</pre></div>
<p>does not execute the tail promise, it just retrieves the variable(s). </p>
<p>While the line </p>
<div class="highlight highlight-ruby"><pre><span class="o">[</span><span class="n">next_stream</span><span class="o">.</span><span class="n">head</span><span class="p">,</span> <span class="n">next_stream</span><span class="o">.</span><span class="n">tail</span><span class="o">]</span>
</pre></div>
<p>would seem to execute it. However, this code works, giving the same results as the above.</p>
Raul Parolari
The 1st Comment on "Infinite Streams"
tag:graysoftinc.com,2007-11-15:/comments/136
2014-03-28T21:17:43Z
Hi, James,
I began to follow the Ruby Forum recently, and from there I discovered your blog. I have a question on this code (I hope that formatting works, if I got Markdown reqs correctly):
```ruby
def drop
result, next_stream = head...
<p>Hi, James,</p>
<p>I began to follow the Ruby Forum recently, and from there I discovered your blog. I have a question on this code (I hope that formatting works, if I got Markdown reqs correctly):</p>
<div class="highlight highlight-ruby"><pre><span class="k">def</span> <span class="nf">drop</span>
<span class="n">result</span><span class="p">,</span> <span class="n">next_stream</span> <span class="o">=</span> <span class="n">head</span><span class="p">,</span> <span class="n">tail</span>
<span class="vi">@head</span><span class="p">,</span> <span class="vi">@tail</span> <span class="o">=</span> <span class="k">if</span> <span class="n">next_stream</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="p">)</span>
<span class="n">next_stream</span><span class="o">.</span><span class="n">instance_eval</span> <span class="p">{</span> <span class="o">[</span><span class="vi">@head</span><span class="p">,</span> <span class="vi">@tail</span><span class="o">]</span> <span class="p">}</span>
<span class="k">else</span>
<span class="c1"># ...</span>
</pre></div>
<p>Why the <code>instance_eval</code>? we have just checked that <code>next_stream</code> is of the class we are in, so we do not need to 'pry' on <code>next_stream</code>; we can just "ask him" (like OO fans like to say) to share its secrets with us spontaneously:</p>
<div class="highlight highlight-ruby"><pre><span class="o">[</span><span class="n">next_stream</span><span class="o">.</span><span class="n">head</span><span class="p">,</span> <span class="n">next_stream</span><span class="o">.</span><span class="n">tail</span><span class="o">]</span>
</pre></div>
<p>I tested it; let me know if I missed something.</p>
<p>One other point, even less important: the name of the method <code>show</code> is a bit curious. It takes a reader (ok, me!) some time to understand the method before he realizes that the intent is to destroy what is read. I would have called <code>show_and_consume</code> (as it consumes everything it reads). Ok, a naming point (but names are important, the last resort as programming becomes more abstract and mysterious by the day).</p>
<p>I have just read a third of the entry, I will devour every bit of it.</p>
Raul Parolari
Infinite Streams
tag:graysoftinc.com,2006-02-20:/posts/9
2014-03-28T21:17:43Z
In this fifth article of the Higher-Order Ruby series, I show how Ruby's classes can improve on the syntax of MJD's lazy streams.
<p>I've tried to summarize this chapter a couple of times now, but I keep getting tripped up over syntax. So, let's talk about that…</p>
<h4>Functional Perl</h4>
<p>Obviously, the examples in the book can be more or less directly translated. Here's a sample from the first couple of pages:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#!/usr/local/bin/ruby -w</span>
<span class="c1">### Stream Methods ###</span>
<span class="k">def</span> <span class="nf">node</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="n">tail</span><span class="p">)</span>
<span class="o">[</span><span class="n">head</span><span class="p">,</span> <span class="n">tail</span><span class="o">]</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">head</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
<span class="n">stream</span><span class="o">.</span><span class="n">first</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">tail</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
<span class="n">tail</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">last</span>
<span class="k">if</span> <span class="n">tail</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Proc</span><span class="p">)</span>
<span class="n">tail</span><span class="o">.</span><span class="n">call</span>
<span class="k">else</span>
<span class="n">tail</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">drop</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
<span class="n">head</span> <span class="o">=</span> <span class="n">head</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
<span class="n">stream</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span><span class="p">,</span> <span class="n">stream</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">(</span><span class="n">tail</span><span class="p">(</span><span class="n">stream</span><span class="p">))</span>
<span class="n">head</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">show</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="n">limit</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="k">while</span> <span class="n">head</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span> <span class="o">&&</span> <span class="p">(</span><span class="n">limit</span><span class="o">.</span><span class="n">nil?</span> <span class="ow">or</span> <span class="p">(</span><span class="n">limit</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">)</span> <span class="o">></span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">print</span> <span class="n">drop</span><span class="p">(</span><span class="n">stream</span><span class="p">),</span> <span class="vg">$,</span> <span class="o">||</span> <span class="s2">" "</span>
<span class="k">end</span>
<span class="nb">print</span> <span class="vg">$/</span>
<span class="k">end</span>
<span class="c1">### Examples ###</span>
<span class="k">def</span> <span class="nf">upto</span><span class="p">(</span><span class="n">from</span><span class="p">,</span> <span class="n">to</span><span class="p">)</span>
<span class="k">return</span> <span class="k">if</span> <span class="n">from</span> <span class="o">></span> <span class="n">to</span>
<span class="n">node</span><span class="p">(</span><span class="n">from</span><span class="p">,</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="n">upto</span><span class="p">(</span><span class="n">from</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">to</span><span class="p">)</span> <span class="p">})</span>
<span class="k">end</span>
<span class="n">show</span><span class="p">(</span><span class="n">upto</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span> <span class="c1"># => 3 4 5 6</span>
<span class="k">def</span> <span class="nf">upfrom</span><span class="p">(</span><span class="n">start</span><span class="p">)</span>
<span class="n">node</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="n">upfrom</span><span class="p">(</span><span class="n">start</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">})</span>
<span class="k">end</span>
<span class="n">show</span><span class="p">(</span><span class="n">upfrom</span><span class="p">(</span><span class="mi">7</span><span class="p">),</span> <span class="mi">10</span><span class="p">)</span> <span class="c1"># => 7 8 9 10 11 12 13 14 15 16</span>
</pre></div>
<p>Already though this is feeling very un-Rubyish, and it will only get worse if we keep going down this path.</p>
<p>I suspect the main reason MJD took such a functional approach with his book is that Perl's objects can be heavy and awkward. That doesn't make for great book examples. Ruby isn't like that though and the previous code is just crying out to be objectified.</p>
<h4>Ruby's Object Orientation</h4>
<p>We will start at the beginning. Clearly we need a constructor. Now the whole point of all this is building lazy streams, so we're always going to be using some head value and a promise for the tail. A promise is a chunk of code, and in Ruby we call that a block:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="o">&</span><span class="n">promise</span><span class="p">)</span>
<span class="vi">@head</span><span class="p">,</span> <span class="vi">@tail</span> <span class="o">=</span> <span class="n">head</span><span class="p">,</span> <span class="n">promise</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>That's already an improvement, since it will allow us to drop the calls to <code>Kernel#lambda</code>. The name is a bit lengthy, but we can easily fix that after we have the rest of this down. For now, we're just tucking our work into a safe namespace.</p>
<p>The next step is to restore access to the head and tail. These are pretty simple readers in this form and while we are building them, let's add some Rubyish aliases:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="kp">attr_reader</span> <span class="ss">:head</span>
<span class="n">alias_method</span> <span class="ss">:current</span><span class="p">,</span> <span class="ss">:head</span>
<span class="k">def</span> <span class="nf">tail</span>
<span class="k">if</span> <span class="vi">@tail</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Proc</span><span class="p">)</span>
<span class="vi">@tail</span><span class="o">.</span><span class="n">call</span>
<span class="k">else</span>
<span class="vi">@tail</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">alias_method</span> <span class="ss">:next</span><span class="p">,</span> <span class="ss">:tail</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>Now, adding back support for drop is where things start to get a little tricky. If a call to <code>LazyStream::Node#tail</code> returns a <code>LazyStream::Node</code>, we want that to replace the current <code>LazyStream::Node</code>. If we get anything else, we'll just assign it normally. Again, here's the code, with aliases:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">drop</span>
<span class="n">result</span><span class="p">,</span> <span class="n">next_stream</span> <span class="o">=</span> <span class="n">head</span><span class="p">,</span> <span class="n">tail</span>
<span class="vi">@head</span><span class="p">,</span> <span class="vi">@tail</span> <span class="o">=</span> <span class="k">if</span> <span class="n">next_stream</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="p">)</span>
<span class="n">next_stream</span><span class="o">.</span><span class="n">instance_eval</span> <span class="p">{</span> <span class="o">[</span><span class="vi">@head</span><span class="p">,</span> <span class="vi">@tail</span><span class="o">]</span> <span class="p">}</span>
<span class="k">else</span>
<span class="nb">Array</span><span class="p">(</span><span class="n">next_stream</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">result</span>
<span class="k">end</span>
<span class="n">alias_method</span> <span class="ss">:tail!</span><span class="p">,</span> <span class="ss">:drop</span>
<span class="n">alias_method</span> <span class="ss">:next!</span><span class="p">,</span> <span class="ss">:drop</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>When using our objectified <code>LazyStream</code>, users won't see a <code>nil</code> return for streams that terminate. Because of that, we should add methods for checking if we are at the end of a stream:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">end?</span>
<span class="vi">@tail</span><span class="o">.</span><span class="n">nil?</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">next?</span>
<span class="o">!</span><span class="k">end</span><span class="p">?</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>Let's add a quick <code>LazyStream::Node#show</code> and see how we have done. We will again toss in an alias, an I'm sorry, but the ugly Perl variables have to go:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">show</span><span class="p">(</span><span class="o">*</span><span class="n">limit_and_options</span><span class="p">)</span>
<span class="n">options</span> <span class="o">=</span> <span class="p">{</span><span class="ss">:sep</span> <span class="o">=></span> <span class="s2">" "</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">}</span><span class="o">.</span><span class="n">merge!</span><span class="p">(</span>
<span class="n">limit_and_options</span><span class="o">.</span><span class="n">last</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Hash</span><span class="p">)</span> <span class="p">?</span> <span class="n">limit_and_options</span><span class="o">.</span><span class="n">pop</span> <span class="p">:</span> <span class="no">Hash</span><span class="o">.</span><span class="n">new</span>
<span class="p">)</span>
<span class="n">limit</span> <span class="o">=</span> <span class="n">limit_and_options</span><span class="o">.</span><span class="n">shift</span>
<span class="k">while</span> <span class="n">head</span> <span class="o">&&</span> <span class="p">(</span><span class="n">limit</span><span class="o">.</span><span class="n">nil?</span> <span class="ow">or</span> <span class="p">(</span><span class="n">limit</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">)</span> <span class="o">></span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">print</span> <span class="n">drop</span><span class="p">,</span> <span class="n">options</span><span class="o">[</span><span class="ss">:sep</span><span class="o">]</span>
<span class="k">end</span>
<span class="nb">print</span> <span class="n">options</span><span class="o">[</span><span class="ss">:end</span><span class="o">]</span>
<span class="k">end</span>
<span class="n">alias_method</span> <span class="ss">:display</span><span class="p">,</span> <span class="ss">:show</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>On with the examples:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#!/usr/local/bin/ruby -w</span>
<span class="nb">require</span> <span class="s2">"lazy_stream"</span>
<span class="k">def</span> <span class="nf">upto</span><span class="p">(</span><span class="n">from</span><span class="p">,</span> <span class="n">to</span><span class="p">)</span>
<span class="k">return</span> <span class="k">if</span> <span class="n">from</span> <span class="o">></span> <span class="n">to</span>
<span class="no">LazyStream</span><span class="o">::</span><span class="no">Node</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">from</span><span class="p">)</span> <span class="p">{</span> <span class="n">upto</span><span class="p">(</span><span class="n">from</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">to</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">upto</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">)</span><span class="o">.</span><span class="n">show</span> <span class="c1"># => 3 4 5 6</span>
<span class="k">def</span> <span class="nf">upfrom</span><span class="p">(</span><span class="n">start</span><span class="p">)</span>
<span class="no">LazyStream</span><span class="o">::</span><span class="no">Node</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">start</span><span class="p">)</span> <span class="p">{</span> <span class="n">upfrom</span><span class="p">(</span><span class="n">start</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">upfrom</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="c1"># => 7 8 9 10 11 12 13 14 15 16</span>
</pre></div>
<p>We're making progress. This is starting to feel more like Ruby. Time for me to make good on my promise for a shorter constructor though. We can just add this to the end of lazy_stream.rb:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">Kernel</span>
<span class="k">def</span> <span class="nf">lazy_stream</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="no">LazyStream</span><span class="o">::</span><span class="no">Node</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>That allows us to trim our functional usage to:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#!/usr/local/bin/ruby -w</span>
<span class="nb">require</span> <span class="s2">"lazy_stream"</span>
<span class="k">def</span> <span class="nf">upto</span><span class="p">(</span><span class="n">from</span><span class="p">,</span> <span class="n">to</span><span class="p">)</span>
<span class="k">return</span> <span class="k">if</span> <span class="n">from</span> <span class="o">></span> <span class="n">to</span>
<span class="n">lazy_stream</span><span class="p">(</span><span class="n">from</span><span class="p">)</span> <span class="p">{</span> <span class="n">upto</span><span class="p">(</span><span class="n">from</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">to</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">upto</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">)</span><span class="o">.</span><span class="n">show</span> <span class="c1"># => 3 4 5 6</span>
<span class="k">def</span> <span class="nf">upfrom</span><span class="p">(</span><span class="n">start</span><span class="p">)</span>
<span class="n">lazy_stream</span><span class="p">(</span><span class="n">start</span><span class="p">)</span> <span class="p">{</span> <span class="n">upfrom</span><span class="p">(</span><span class="n">start</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">upfrom</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="c1"># => 7 8 9 10 11 12 13 14 15 16</span>
</pre></div>
<p>Even better though, this is Ruby and we can make full objects:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#!/usr/local/bin/ruby -w</span>
<span class="nb">require</span> <span class="s2">"lazy_stream"</span>
<span class="k">class</span> <span class="nc">Upto</span> <span class="o"><</span> <span class="no">LazyStream</span><span class="o">::</span><span class="no">Node</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">from</span><span class="p">,</span> <span class="n">to</span><span class="p">)</span>
<span class="k">if</span> <span class="n">from</span> <span class="o">></span> <span class="n">to</span>
<span class="k">super</span><span class="p">(</span><span class="kp">nil</span><span class="p">,</span> <span class="o">&</span><span class="kp">nil</span><span class="p">)</span>
<span class="k">else</span>
<span class="k">super</span><span class="p">(</span><span class="n">from</span><span class="p">)</span> <span class="p">{</span> <span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">from</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">to</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Upto</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">)</span><span class="o">.</span><span class="n">show</span> <span class="c1"># => 3 4 5 6</span>
<span class="k">class</span> <span class="nc">Upfrom</span> <span class="o"><</span> <span class="no">LazyStream</span><span class="o">::</span><span class="no">Node</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">from</span><span class="p">)</span>
<span class="k">super</span><span class="p">(</span><span class="n">from</span><span class="p">)</span> <span class="p">{</span> <span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">from</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Upfrom</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="c1"># => 7 8 9 10 11 12 13 14 15 16</span>
</pre></div>
<p>Now we can have our interface any way we like it. Some things still need work though…</p>
<h4>Inside-out Iteration</h4>
<p>So far, I've just copied MJD's external iterator interface. Those are certainly helpful with lazy streams, because you may want to pull values for a while, stop to do something else, and come back to the stream later.</p>
<p>However, Ruby just doesn't feel right without an <code>#each</code> method and <code>Enumerable</code> mixed-in. In this particular case, we really want two forms of iteration, one each for <code>LazyStream::Node#tail</code> and <code>LazyStream::Node#drop</code> so we can advance the stream, or just peek ahead.</p>
<p>It's easier to build the destructive version first. In fact, we already have the implementation coded up inside <code>LazyStream::Node#show</code>. Let's even keep the limit as a handy way to keep from going too deep:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">each!</span><span class="p">(</span><span class="n">limit</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="kp">loop</span> <span class="k">do</span>
<span class="k">break</span> <span class="k">unless</span> <span class="n">limit</span><span class="o">.</span><span class="n">nil?</span> <span class="o">||</span> <span class="p">(</span><span class="n">limit</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">)</span> <span class="o">></span> <span class="o">-</span><span class="mi">1</span>
<span class="k">yield</span><span class="p">(</span><span class="n">drop</span><span class="p">)</span>
<span class="k">break</span> <span class="k">if</span> <span class="k">end</span><span class="p">?</span>
<span class="k">end</span>
<span class="nb">self</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>Then we can use that to build the standard iterator:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">each</span><span class="p">(</span><span class="n">limit</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="nb">clone</span><span class="o">.</span><span class="n">each!</span><span class="p">(</span><span class="n">limit</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="nb">self</span>
<span class="k">end</span>
<span class="n">alias_method</span> <span class="ss">:peek</span><span class="p">,</span> <span class="ss">:each</span>
<span class="kp">include</span> <span class="no">Enumerable</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>That let's us use standard Ruby iteration, for the most part. We can even set a limit to keep from going too far. We can also use methods like <code>Enumerable#find</code> on an infinite stream, since it will stop as soon as it finds a match.</p>
<p>Where this system has trouble is if we want to use something like <code>Enumerable#map</code> on an infinite stream. The problem here is that we have no good way to pass the limit down. It's also tricky to use <code>LazyStream::Node#each!</code> with the <code>Enumerable</code> methods. Let's fix both issues:</p>
<div class="highlight highlight-ruby"><pre><span class="nb">require</span> <span class="s2">"enumerator"</span>
<span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">limit</span><span class="p">(</span><span class="n">max_depth</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="n">enum_for</span><span class="p">(</span><span class="ss">:each</span><span class="p">,</span> <span class="n">max_depth</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">limit!</span><span class="p">(</span><span class="n">max_depth</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="n">enum_for</span><span class="p">(</span><span class="ss">:each!</span><span class="p">,</span> <span class="n">max_depth</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>There's a little black magic there we need to see in action, but before we go back to examples we can simplify <code>LazyStream::Node#show</code> to use the new iterators:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">show</span><span class="p">(</span><span class="o">*</span><span class="n">limit_and_options</span><span class="p">)</span>
<span class="n">options</span> <span class="o">=</span> <span class="p">{</span><span class="ss">:sep</span> <span class="o">=></span> <span class="s2">" "</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">}</span><span class="o">.</span><span class="n">merge!</span><span class="p">(</span>
<span class="n">limit_and_options</span><span class="o">.</span><span class="n">last</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Hash</span><span class="p">)</span> <span class="p">?</span> <span class="n">limit_and_options</span><span class="o">.</span><span class="n">pop</span> <span class="p">:</span> <span class="no">Hash</span><span class="o">.</span><span class="n">new</span>
<span class="p">)</span>
<span class="n">limit</span> <span class="o">=</span> <span class="n">limit_and_options</span><span class="o">.</span><span class="n">shift</span>
<span class="n">each</span><span class="p">(</span><span class="n">limit</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">cur</span><span class="o">|</span> <span class="nb">print</span> <span class="n">cur</span><span class="p">,</span> <span class="n">options</span><span class="o">[</span><span class="ss">:sep</span><span class="o">]</span> <span class="p">}</span>
<span class="nb">print</span> <span class="n">options</span><span class="o">[</span><span class="ss">:end</span><span class="o">]</span>
<span class="k">end</span>
<span class="n">alias_method</span> <span class="ss">:display</span><span class="p">,</span> <span class="ss">:show</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>Okay, let's see what we have created. Here's an infinite stream iterator, using <code>Enumerable#map</code>:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#!/usr/local/bin/ruby -w</span>
<span class="nb">require</span> <span class="s2">"lazy_stream"</span>
<span class="k">class</span> <span class="nc">Step</span> <span class="o"><</span> <span class="no">LazyStream</span><span class="o">::</span><span class="no">Node</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">step</span><span class="p">,</span> <span class="n">start</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">super</span><span class="p">(</span><span class="n">start</span><span class="p">)</span> <span class="p">{</span> <span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">step</span><span class="p">,</span> <span class="n">start</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">}</span>
<span class="vi">@step</span> <span class="o">=</span> <span class="n">step</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">next_group</span><span class="p">(</span><span class="n">count</span> <span class="o">=</span> <span class="mi">10</span><span class="p">)</span>
<span class="n">limit!</span><span class="p">(</span><span class="n">count</span><span class="p">)</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">i</span><span class="o">|</span> <span class="n">i</span> <span class="o">*</span> <span class="vi">@step</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">evens</span> <span class="o">=</span> <span class="no">Step</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"The first ten even numbers are:"</span>
<span class="nb">puts</span> <span class="n">evens</span><span class="o">.</span><span class="n">next_group</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">" "</span><span class="p">)</span> <span class="c1"># => 2 4 6 8 10 12 14 16 18 20</span>
<span class="c1"># later...</span>
<span class="nb">puts</span>
<span class="nb">puts</span> <span class="s2">"The next ten even numbers are:"</span>
<span class="nb">puts</span> <span class="n">evens</span><span class="o">.</span><span class="n">next_group</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">" "</span><span class="p">)</span> <span class="c1"># => 22 24 26 28 30 32 34 36 38 40</span>
<span class="nb">puts</span>
<span class="nb">puts</span> <span class="s2">"The current index for future calculations is:"</span>
<span class="nb">puts</span> <span class="n">evens</span><span class="o">.</span><span class="n">current</span> <span class="c1"># => 21</span>
</pre></div>
<p>That feels a lot more like Ruby to me. Now we can get back to MJD's examples.</p>
<h4>Adding <code>#filter</code> and <code>#transform</code>
</h4>
<p>MJD adds both a <code>#filter</code> and <code>#transform</code> method next. Technically, my last example is a transformation of the stream and we could do filtering the same way. Still it's nice to have these built-in and we should add them.</p>
<p>The <code>#filter</code> is easy enough, we just have to keep dropping items until we find a match and make sure setting a filter is viral to future nodes:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">tail</span>
<span class="n">result</span> <span class="o">=</span> <span class="k">if</span> <span class="vi">@tail</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Proc</span><span class="p">)</span>
<span class="vi">@tail</span><span class="o">.</span><span class="n">call</span>
<span class="k">else</span>
<span class="vi">@tail</span>
<span class="k">end</span>
<span class="n">result</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="vi">@filter</span><span class="p">)</span> <span class="k">unless</span> <span class="vi">@filter</span><span class="o">.</span><span class="n">nil?</span> <span class="o">||</span> <span class="o">!</span><span class="n">result</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="p">)</span>
<span class="n">result</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">filter</span><span class="p">(</span><span class="n">pattern</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="vi">@filter</span> <span class="o">=</span> <span class="n">pattern</span> <span class="o">||</span> <span class="n">block</span>
<span class="n">drop</span> <span class="k">until</span> <span class="n">matches_filter?</span><span class="p">(</span><span class="vi">@head</span><span class="p">)</span>
<span class="nb">self</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">matches_filter?</span><span class="p">(</span><span class="n">current</span><span class="p">)</span>
<span class="k">case</span> <span class="vi">@filter</span>
<span class="k">when</span> <span class="kp">nil</span>
<span class="kp">true</span>
<span class="k">when</span> <span class="no">Proc</span>
<span class="vi">@filter</span><span class="o">[</span><span class="n">current</span><span class="o">]</span>
<span class="k">else</span>
<span class="vi">@filter</span> <span class="o">===</span> <span class="n">current</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>We can add <code>#transform</code> by defining an actual getter for <code>@head</code>, instead of the <code>attr_reader</code> shortcut I've been using and, again, making the setting viral:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">head</span>
<span class="vi">@transformer</span><span class="o">.</span><span class="n">nil?</span> <span class="p">?</span> <span class="vi">@head</span> <span class="p">:</span> <span class="vi">@transformer</span><span class="o">[</span><span class="vi">@head</span><span class="o">]</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">tail</span>
<span class="n">result</span> <span class="o">=</span> <span class="k">if</span> <span class="vi">@tail</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Proc</span><span class="p">)</span>
<span class="vi">@tail</span><span class="o">.</span><span class="n">call</span>
<span class="k">else</span>
<span class="vi">@tail</span>
<span class="k">end</span>
<span class="n">result</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="vi">@filter</span><span class="p">)</span> <span class="k">unless</span> <span class="vi">@filter</span><span class="o">.</span><span class="n">nil?</span> <span class="o">||</span>
<span class="o">!</span><span class="n">result</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="p">)</span>
<span class="n">result</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="o">&</span><span class="vi">@transformer</span><span class="p">)</span> <span class="k">unless</span> <span class="vi">@transformer</span><span class="o">.</span><span class="n">nil?</span> <span class="o">||</span>
<span class="o">!</span><span class="n">result</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="p">)</span>
<span class="n">result</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">transform</span><span class="p">(</span><span class="o">&</span><span class="n">transformer</span><span class="p">)</span>
<span class="vi">@transformer</span> <span class="o">=</span> <span class="n">transformer</span>
<span class="nb">self</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>Here are trivial examples with both:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#!/usr/local/bin/ruby -w</span>
<span class="nb">require</span> <span class="s2">"lazy_stream"</span>
<span class="k">def</span> <span class="nf">letters</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="n">lazy_stream</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span> <span class="p">{</span> <span class="n">letters</span><span class="p">(</span><span class="n">letter</span><span class="o">.</span><span class="n">succ</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">letters</span><span class="p">(</span><span class="s2">"a"</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="sr">/[aeiou]/</span><span class="p">)</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="c1"># => a e i o u aa ab ac ad ae</span>
<span class="n">letters</span><span class="p">(</span><span class="s2">"a"</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span> <span class="p">{</span> <span class="o">|</span><span class="n">l</span><span class="o">|</span> <span class="n">l</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="mi">2</span> <span class="p">}</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># => aa ab ac </span>
<span class="n">letters</span><span class="p">(</span><span class="s2">"a"</span><span class="p">)</span><span class="o">.</span><span class="n">transform</span> <span class="p">{</span> <span class="o">|</span><span class="n">l</span><span class="o">|</span> <span class="n">l</span> <span class="o">+</span> <span class="s2">"..."</span> <span class="p">}</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># => a... b... c...</span>
</pre></div>
<h4>Recursive Streams</h4>
<p>I think we can fix the recursive issues MJD discusses with ease in our Ruby version, just by passing the stream head to the promise block:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">tail</span>
<span class="n">result</span> <span class="o">=</span> <span class="k">if</span> <span class="vi">@tail</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Proc</span><span class="p">)</span>
<span class="vi">@tail</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">head</span><span class="p">)</span>
<span class="k">else</span>
<span class="vi">@tail</span>
<span class="k">end</span>
<span class="k">unless</span> <span class="n">result</span> <span class="o">==</span> <span class="vi">@tail</span>
<span class="n">result</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="vi">@filter</span><span class="p">)</span> <span class="k">unless</span> <span class="vi">@filter</span><span class="o">.</span><span class="n">nil?</span> <span class="o">||</span>
<span class="o">!</span><span class="n">result</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="p">)</span>
<span class="n">result</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="o">&</span><span class="vi">@transformer</span><span class="p">)</span> <span class="k">unless</span> <span class="vi">@transformer</span><span class="o">.</span><span class="n">nil?</span> <span class="o">||</span>
<span class="o">!</span><span class="n">result</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="p">)</span>
<span class="k">end</span>
<span class="vi">@tail</span> <span class="o">=</span> <span class="n">result</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>With that, MJD's example is trivial:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#!/usr/local/bin/ruby -w</span>
<span class="nb">require</span> <span class="s2">"lazy_stream"</span>
<span class="k">class</span> <span class="nc">Powers</span> <span class="o"><</span> <span class="no">LazyStream</span><span class="o">::</span><span class="no">Node</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">of</span><span class="p">,</span> <span class="n">start</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">super</span><span class="p">(</span><span class="n">start</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">last</span><span class="o">|</span> <span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">of</span><span class="p">,</span> <span class="n">last</span> <span class="o">*</span> <span class="n">of</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">powers_of_two</span> <span class="o">=</span> <span class="no">Powers</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">powers_of_two</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="c1"># => 1 2 4 8 16 32 64 128 256 512</span>
</pre></div>
<p>In all honesty though, you seldom need that with the blocks being closures. You can just reference the local variables instead.</p>
<p>You also don't need merging to solve the Hamming Sequence. Here's a simple example:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#!/usr/local/bin/ruby -w</span>
<span class="nb">require</span> <span class="s2">"lazy_stream"</span>
<span class="k">class</span> <span class="nc">Hamming</span> <span class="o"><</span> <span class="no">LazyStream</span><span class="o">::</span><span class="no">Node</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">seq</span> <span class="o">=</span> <span class="o">[</span><span class="mi">1</span><span class="o">]</span><span class="p">)</span>
<span class="n">cur</span> <span class="o">=</span> <span class="n">seq</span><span class="o">.</span><span class="n">shift</span>
<span class="k">super</span><span class="p">(</span><span class="n">cur</span><span class="p">)</span> <span class="k">do</span>
<span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">new</span><span class="p">((</span><span class="n">seq</span> <span class="o"><<</span> <span class="n">cur</span> <span class="o">*</span> <span class="mi">2</span> <span class="o"><<</span> <span class="n">cur</span> <span class="o">*</span> <span class="mi">3</span> <span class="o"><<</span> <span class="n">cur</span> <span class="o">*</span> <span class="mi">5</span><span class="p">)</span><span class="o">.</span><span class="n">uniq</span><span class="o">.</span><span class="n">sort</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Hamming</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span> <span class="c1"># => 1 2 3 4 5 6 8 9 10 12 15 16 18 20 24</span>
</pre></div>
<h4>Regexp String Generation</h4>
<p>We don't need too many modifications to be able to create this example. First, let's build a <code>LazyStream::union</code>:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">union</span><span class="p">(</span><span class="o">*</span><span class="n">streams</span><span class="p">)</span>
<span class="n">current</span> <span class="o">=</span> <span class="n">streams</span><span class="o">.</span><span class="n">shift</span> <span class="ow">or</span> <span class="k">return</span>
<span class="no">Node</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">current</span><span class="o">.</span><span class="n">head</span><span class="p">)</span> <span class="p">{</span> <span class="n">union</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">streams</span> <span class="o"><<</span> <span class="n">current</span><span class="o">.</span><span class="n">tail</span><span class="p">))</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>We can even add a little syntax sugar for calling that:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">+</span><span class="p">(</span><span class="n">other_stream</span><span class="p">)</span>
<span class="no">LazyStream</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="nb">self</span><span class="p">,</span> <span class="n">other_stream</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>Finally, because I made <code>LazyStream::Node#transform</code> modify the stream, we will need a <code>LazyStream::Node#dup</code> to build MJD's <code>#concat</code> method:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">LazyStream</span>
<span class="k">class</span> <span class="nc">Node</span>
<span class="k">def</span> <span class="nf">dup</span>
<span class="k">if</span> <span class="n">tail</span><span class="o">.</span><span class="n">nil?</span> <span class="o">||</span> <span class="n">tail</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Proc</span><span class="p">)</span>
<span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">new</span><span class="p">(</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="k">else</span>
<span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">head</span><span class="p">)</span> <span class="p">{</span> <span class="n">tail</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>From there we can build a <code>RegexpMatchesGenerator</code>:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#!/usr/local/bin/ruby -w</span>
<span class="nb">require</span> <span class="s2">"lazy_stream"</span>
<span class="k">module</span> <span class="nn">RegexpMatchesGenerator</span>
<span class="kp">extend</span> <span class="nb">self</span>
<span class="k">def</span> <span class="nf">literal</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
<span class="n">lazy_stream</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">concat</span><span class="p">(</span><span class="n">stream1</span><span class="p">,</span> <span class="n">stream2</span><span class="p">)</span>
<span class="n">lazy_stream</span><span class="p">(</span><span class="n">stream1</span><span class="o">.</span><span class="n">head</span> <span class="o">+</span> <span class="n">stream2</span><span class="o">.</span><span class="n">head</span><span class="p">)</span> <span class="k">do</span>
<span class="n">combinations</span> <span class="o">=</span> <span class="nb">Array</span><span class="o">.</span><span class="n">new</span>
<span class="k">unless</span> <span class="n">stream1</span><span class="o">.</span><span class="n">end?</span>
<span class="n">combinations</span> <span class="o"><<</span> <span class="n">stream1</span><span class="o">.</span><span class="n">tail</span><span class="o">.</span><span class="n">dup</span><span class="o">.</span><span class="n">transform</span> <span class="p">{</span> <span class="o">|</span><span class="n">str</span><span class="o">|</span> <span class="n">str</span> <span class="o">+</span> <span class="n">stream2</span><span class="o">.</span><span class="n">head</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">unless</span> <span class="n">stream2</span><span class="o">.</span><span class="n">end?</span>
<span class="n">combinations</span> <span class="o"><<</span> <span class="n">stream2</span><span class="o">.</span><span class="n">tail</span><span class="o">.</span><span class="n">dup</span><span class="o">.</span><span class="n">transform</span> <span class="p">{</span> <span class="o">|</span><span class="n">str</span><span class="o">|</span> <span class="n">stream1</span><span class="o">.</span><span class="n">head</span> <span class="o">+</span> <span class="n">str</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">unless</span> <span class="n">stream1</span><span class="o">.</span><span class="n">end?</span> <span class="o">||</span> <span class="n">stream2</span><span class="o">.</span><span class="n">end?</span>
<span class="n">combinations</span> <span class="o"><<</span> <span class="n">concat</span><span class="p">(</span><span class="n">stream1</span><span class="o">.</span><span class="n">tail</span><span class="p">,</span> <span class="n">stream2</span><span class="o">.</span><span class="n">tail</span><span class="p">)</span>
<span class="k">end</span>
<span class="no">LazyStream</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="o">*</span><span class="n">combinations</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">star</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="n">head</span> <span class="o">=</span> <span class="s2">""</span><span class="p">)</span>
<span class="n">lazy_stream</span><span class="p">(</span><span class="n">head</span><span class="p">)</span> <span class="p">{</span> <span class="n">star</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="n">head</span> <span class="o">+</span> <span class="n">stream</span><span class="o">.</span><span class="n">head</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">char_class</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
<span class="no">LazyStream</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="o">*</span><span class="n">string</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">str</span><span class="o">|</span> <span class="n">literal</span><span class="p">(</span><span class="n">str</span><span class="p">)</span> <span class="p">})</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">plus</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
<span class="n">star</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">head</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">if</span> <span class="bp">__FILE__</span> <span class="o">==</span> <span class="vg">$0</span>
<span class="kp">include</span> <span class="no">RegexpMatchesGenerator</span>
<span class="c1"># /^(a|b)(c|d)$/</span>
<span class="n">concat</span><span class="p">(</span><span class="n">literal</span><span class="p">(</span><span class="s2">"a"</span><span class="p">)</span> <span class="o">+</span> <span class="n">literal</span><span class="p">(</span><span class="s2">"b"</span><span class="p">),</span> <span class="n">literal</span><span class="p">(</span><span class="s2">"c"</span><span class="p">)</span> <span class="o">+</span> <span class="n">literal</span><span class="p">(</span><span class="s2">"d"</span><span class="p">))</span><span class="o">.</span><span class="n">show</span>
<span class="c1"># /^(HONK)*$/</span>
<span class="nb">puts</span> <span class="n">star</span><span class="p">(</span><span class="n">literal</span><span class="p">(</span><span class="s2">"HONK"</span><span class="p">))</span><span class="o">.</span><span class="n">limit</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">str</span><span class="o">|</span> <span class="n">str</span><span class="o">.</span><span class="n">inspect</span> <span class="p">}</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">" "</span><span class="p">)</span>
<span class="c1"># /^ab*$/</span>
<span class="nb">puts</span><span class="p">(</span><span class="n">concat</span><span class="p">(</span><span class="n">literal</span><span class="p">(</span><span class="s2">"a"</span><span class="p">),</span> <span class="n">star</span><span class="p">(</span><span class="n">literal</span><span class="p">(</span><span class="s2">"b"</span><span class="p">)))</span><span class="o">.</span><span class="n">limit</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span><span class="o">.</span><span class="n">to_a</span><span class="p">)</span>
<span class="k">end</span>
</pre></div>
<h4>The Rest</h4>
<p>That should be enough example translation to address most of the highlights from this chapter. All those math problems at the end make me drowsy, so I'll leave those as an exercise for the reader…</p>
James Edward Gray II