

10.unfold { |n| n-1 unless n == 1 }.inspect => [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

10.class.unfold(&:superclass).inspect => [Fixnum, Integer, Numeric, Object]



5.unfold(&'_-1 unless _==1').inject(&'*') => 120

I was reading Code Complete 2 last night and Steve McConnell says that he wouldn’t hire a programmer who wrote a recursive factorial function. [I’m not sure that would be such a crime in languages like Lua with proper tail recursion, but still. (I’m probably wrong, now I’ve written that! “Open mouth, insert foot, echo internationally” as they used to say on Fidonet :-))] I thought “that seems a bit harsh”, especially since in real life they’d get one from a library most of the time, anyway.



So, as I have often run out of stack on Ruby, I’ve tried to rewrite unfold as an iterative function. It seems to be working. The script as modified blows up at 5000 on my system with the recursive version, but the iterative version succeeds at 5000.



Thanks for this blog entry. There’s something REALLY nice about this idea, which I can’t put my finger on. Might be something to do with loops terminating when they should, and The Pragmatic Programmers’ article about “cook until done”



http://www.pragprog.com/articles/cook-until-done



Unfold feels like a “do until finished” loop.





class Object

# As above, but iterative, rather than recursive.

def unfold2 &block

result = [self]

x = block.call(self)

while not x.nil?

result.push x

x = block.call(x)

end

return result

end

end



Labels: lispy, popular, ruby