On Nov 1, 6:36 am, Robert Klemme <shortcut... / googlemail.com> wrote: > On 01.11.2008 09:58, Yuh-Ruey Chen wrote: > > > Two questions: > > > 1) Are there equivalents for iteration/enumeration functions like map > > that return iterator/enumeration objects (in a Python sense)? > > > An example: > > > def read_files(files) > > files.each {|file| > > # blah > > } > > end > > read_file(['file1', 'file2', 'file3'].map_iter {|x| open(x)}) > > # map_iter would return an iterator object immediately instead of > > opening every file and storing them into an array > > There is one issue with this design: the IO object is not closed properly. > > > I know that I could do this instead: > > > ['file1', 'file2', 'file3'].each {|x| > > open(x) { > > # blah > > } > > } > > > but sometimes it's inconvenient to do that if there's already a > > function that accepts an Enumerable such as read_files above. > > So read_files expects an enumeration of opened IO objects, I guess. And > you want to make sure that files are only opened on demand, correct? That was really just a random example that I thought up quickly to explain my question. Others have already posted better examples. > Your approach feels a bit off the usual Ruby way and I am suspecting > that you are trying to force foreign patterns into the language. Per my previous reply, I'm trying to find a way to chain iterators without nesting blocks (so they can be passed freely into other functions expecting enumerables) and without intermediate arrays. > > 2) Is there some lazy evaluation library that can recalculate lazy > > expression when values change? Something with the following semantics > > (or something like it): > > > x = lazy {a + b} > > a = 1 > > b = 2 > > p x # 3 (calculates a + b) > > This cannot work IMHO since local variables a and b are defined *after* > the block. > > > p x # 3 (memoized value) > > a = 3 > > p x # 5 (recalculates a + b) > > a = [1,2] > > b = [3,4] > > p x # [1,2,3,4] (recalculates a + b) > > p x # [1,2,3,4] (memoized value) > > a[1] = '.' > > p x # [1,'.',3,4] (recalculates a + b) > > > I know there's a library called lazy.rb, but it's not exactly what I'm > > looking for as it doesn't implement this functionality. > > IMHI you better explicitly provide arguments to whatever you use to > lazily calculate values. One way is memoize and another option is to > use a Hash for this if there is just one argument: > > irb(main):023:0> square = Hash.new {|h,k| puts "called"; h[k] = k * k} > => {} > irb(main):024:0> square[1000000] > called > => 1000000000000 > irb(main):025:0> square[1000000] > => 1000000000000 > irb(main):026:0> square[1000000] > => 1000000000000 > irb(main):027:0> > > If you have more arguments, you can do > > def lazy(&b) > cache = {} > lambda {|*a| cache[a] ||= b[*a]} > end > > irb(main):006:0> plus2 = lazy {|a,b| puts "called #{a} + #{b}"; a+b} > => #<Proc:0x7ff8c2d8@(irb):3> > irb(main):007:0> plus2[1,2] > called 1 + 2 > => 3 > irb(main):008:0> plus2[1,2] > => 3 > irb(main):009:0> plus2[2,1] > called 2 + 1 > => 3 > irb(main):010:0> plus2[2,1] > => 3 > irb(main):011:0> > > Kind regards > > robert Hmm, what I'm looking for is not just a simple memoization technique. Suppose I have a function that computes the union of two arrays whenever each array is changed. Using a perhaps more possible syntax: attr_accessor :array_a def foo lazy_union = lazy_expr { lazy_depends(:array_a) + lazy_depends(:array_b) } @array_a = [1,2] @array_b = [3,4] p lazy_union # [1,2,3,4] @array_a[1] = 5 p lazy_union # [1,5,3,4] end This is a case your memoization technique doesn't address. Yet I'm pretty sure this is a common use case, so I was thinking that there should be some library out there that provides this functionality.