temp=some_collection.select do |each|Basically, the lazy enumerable combines the blocks for the collect and select into one and will not calculate the merged collection until some method like each or size is called. So, how do you do that? Well, the code for calling each on the LazyEnumerable looks like this:
each.is_interesting
end
answer=temp collect {|each| each.to_something}
def each(&proc)I simply call each on the original collection and then call the block defined in myself (which I call monadic) that simply transforms values when called. Now, I return a special value if it should be ignored. This will be covered when you add a select block. For now, let's look at the simple case of adding a block that collects:
self.original.each do |each|
if (self.monadic.nil?)
answer=each
else
answer=self.monadic.call(each)
end
proc.call(answer) unless answer === IGNOREABLE_OBJECT
end
end
def add_collect(&proc)This passes straight through to this method:
add_monadic_valuable(&proc)
end
def add_monadic_valuable(&proc)The interesting part is when I set my instance variable, monadic. I'm basically combining the current monadic with the new one passed in. Pretty cool, huh? I think this is the kind of stuff that functional programmers love. I can see why. It feels right. Now, let's look at how to add a select block:
current=self.monadic
if (current.nil?)
self.monadic=proc
return self
end
self.monadic=lambda do |each|
result=current.call(each)
if (result === IGNOREABLE_OBJECT)
result
else
proc.call(result)
end
end
self
end
def add_select(&proc)
add_monadic_valuable do |each|
if (proc.call(each))
each
else
IGNOREABLE_OBJECT
end
end
end
All I do is call the same add_monadic_valuable method, but with a twist. I create yet another block that calls the select block inside to see if the value is true or false. If false, we pass back that IGNOREABLE_OBJECT. In the Smalltalk version, I originally threw an exception but took it out when the performance suffered. So, in short, I simply turn my select into a special case of collect! Now, how do I support rejects? Do I copy the code for select and use unless? Nope, all I do is negate the reject block before I send it into the add_select method. How do you do that? Like this:
- class Proc
def negate
lambda {|each| !self.call(each)}
end
end
No comments:
Post a Comment