From: HarryO Date: 2001-10-04T20:07:13+09:00 Subject: [ruby-talk:22076] Re: Marshal won't dump a Proc In article , "Phil Tomson" wrote: > I'm not sure I totally understand what you are doing, but it seems like > you're having the user supply a function to your class (a Proc) that is > used to supply a sequence of numbers (am I right?). Yes. That's basically right. The concept came from some perl code that was discussed here a while back. The idea is to have what looks like a stream of numbers (although, I guess it could potentially be anything, really) that looks like an array, in that when you ask for the next item out of the array it looks like it's "just there". What actually happens is that when you ask for an item, the block that was passed when constructing this type of object is called however many times are necessary to calculate the array entries up to the one the user requested. This, in itself, isn't overly useful, other than providing an abstraction for anyone who wants to use that sequence. However, the other neat idea was to merge a number of these types of sequences together, thus obtaining things in order. The classic example that was what opened the discussion last time, was to generate all of the numbers that are 2^i * 3^j * 5^k, in order. The pair of classes I've created provide this functionality in ruby (not quite ready for public consumption yet, though). >What if you had a > module called UserSupplied (for example) that got included into your > class? The user would have to define a function in the UserSupplied > module. This is a nice idea, except that I think it separates things more than I'd like. I basically want the user to be able to say something like (and this is currently how it works) ... note that this isn't a particularly useful example, I just want to keep it simple ... powersOf2 = Stream.new([1]) { |s, i| s[i - 1] * 2 } The array parameter is whatever necessary initial values are required to start the sequence off. For some cases, there won't be any, for some there will be more than one value (see the example ahead). Ie, the block is passed a reference to the Stream, plus the index of the item that is required and its return value is that array item. It can refer to any of the previous entries in order to calculate it. For example, fibonacci = Stream.new([1, 1]) { |s, i| s[i - 2] + s[i - 1] } This is definitely not the most efficient way to generate such a sequence, since there's a function call overhead for the generation of each item. However, the facility to merge streams together provides for neat approaches to solve some problems. I assume you can see now why I think it's nicer to keep the block that does the calculations close to where the stream is defined. It just makes it easier for someone reading the code, rather than having to go off to look at another module. I'll have more of a think about what you've suggested, though, since it may be another orthogonal way of providing the specification of the calculation and there's no reason not to allow people to have more than one way to do things, even if that is another language's idiom :-). > Would this work for you? I guess the drawback is that your users would > have to know Ruby, This is intended for the ruby literate, so that's not an issue for me.