Lazy evaluation of infinite enumerator in Ruby 1.9 - calling instance method on object from different class -
i'm trying grips lazy evaluation of enumerator using ruby 1.9. work in progress have other bugs/missing code have 1 specific problem right now. i'm trying pass test (note cannot change test):
def test_enumerating_with_a_single_enumerator enumerator = someclass.new(some_infinite_sequence.to_enum) assert_equal [1, 2, 3, 4, 5], enumerator.take(5) end i've written code below , know problem i'm calling lazy_select instance method someclass on argument initialize method instance of enumerator class, nomethoderror. suggestions? thank you.
class someclass < enumerator def initialize(*enumerators) super() |yielder| enumerators.each |enumerator| enumerator.lazy_select { |yielder, first_value, second_value| yielder.yield first_value if (first_value <=> second_value) <= 0 } .first(20) end end end def lazy_select(&block) self.class.new |yielder| each_cons(2) |first_value, second_value| block.call(yielder, first_value, second_value) end end end end
i have 1 specific problem right now. i'm trying pass test (note cannot change test):
def test_enumerating_with_a_single_enumerator enumerator = someclass.new(some_infinite_sequence.to_enum) assert_equal [1, 2, 3, 4, 5], enumerator.take(5) end
class someclass < enumerator def initialize(enum, &block) super() |y| begin enum.each |val| if block block.call(y, val) #while initializing sc2 in line b execution takes branch else y << val #while initializing sc1 line execution halts here end end rescue stopiteration end end end def lazy_take(n) taken = 0 someclass.new(self) |y, val| #line b if taken < n y << val taken += 1 else raise stopiteration end end end def take(n) lazy_take(n).to_a end end sc1 = someclass.new( (1..6).cycle ) #line p sc1.take(10) --output:-- [1, 2, 3, 4, 5, 6, 1, 2, 3, 4] sc2 name i'm giving anonymous instance created inside lazy_take().
the code difficult understand. code sets things sc1's enumerator cycle, , sc2's enumerator sc1 (initialize() requires first arg enumerator). when sc1 initialized, code starts stepping through values in cycle , halts @ line:
y << val then when lazy_take() called, sc2 created, , initialization code starts stepping through values in sc1. there no values in sc1, sc1 executes line:
y << val to inject value cycle sc1's yielder. sc1's yielder yields val sc2--because in sc2's code each() method demanding value sc1. sc2 takes val , injects sc2's yielder. next iteration of each block in sc2 takes place, , once again sc2's code demands value sc1. sc2 repeatedly demands value sc1, causes sc1 pass on value retrieved cycle. once sc2 runs loop n times, stops demanding values sc1. next step make sc2 give values in it's yielder.
if prefer, can define initialize() this:
def initialize(enum) super() |y| begin enum.each |val| if block_given? yield y, val #while initializing sc2 in line b execution takes branch else y << val #while initializing sc1 line execution halts here end end rescue stopiteration end end end that shows not have specify block parameter , explicitly call() block. instead, can dispense block parameter , call yield(), , values sent block automatically.
Comments
Post a Comment