Search code examples
ruby-on-railsrubyfunctional-programminglazy-evaluationenumerator

Ruby Enumerator-based lazy flatten method


Michael Harrison has a great post on lazy enumerators in Ruby, providing an implementation of lazy_select and lazy_map. I am wondering whether the following implementation of lazy_flatten should have special processing for anything other than Enumerator and Enumerable types.

class Enumerator

  def lazy_flatten
    Enumerator.new do |yielder|
      self.each do |value|
        if value.kind_of? Enumerator
          value.lazy_flatten.each do |v|
            yielder.yield v
          end
        elsif value.kind_of? Enumerable
          value.flatten.each do |v|
            yielder.yield v
          end
        else
          yielder.yield value
        end
      end
    end
  end

end

Solution

    1. This doesn't seem lazy to me, as you are still performing old (non-lazy) flatten beneath.
    2. Enumerator is Enumerable, so I think you don't need to handle it separately.
    3. I would expect lazy_flatten to be method on Enumerable.

    Here's how I would implement it:

    module Enumerable
      def lazy_flatten
        Enumerator.new do |yielder|
          each do |element|
            if element.is_a? Enumerable
              element.lazy_flatten.each do |e|
                yielder.yield(e)
              end
            else
              yielder.yield(element)
            end
          end
        end
      end
    end