> better?
>
>  class CachedLambda < Struct.new(:block, :cache)

If we're thinking Lispy, well, why don't we stay in that
mode?... ;]

We could implement such a cache for lambda functions with one,
uh, two, more lambda functions...

----------------------------------------------------------------

 fac	= lambda{|n| n < 2 ? 1 : (1..n).inject{|f, i| f * i}}
 tri	= lambda{|n, r| fac[n] / (fac[r] * fac[n-r])}
 size	= lambda{|r| tri[r-1, r / 2].to_s.size + 1}
 line	= lambda{|y, r| (0..y).map{|x| tri[y,x].to_s.center size[r]}}
 lines	= lambda{|r| (0...r).map{|y| line[y, r]}}
 pascal	= lambda{|r| lines[r].map{|l| l.join.center(size[r]*r).rstrip}}

 cache	= lambda{|f| h={} ; lambda{|*args| h[args] ||= f[*args]}}

 fac	= cache[fac]
 tri	= cache[tri]
 size	= cache[size]
 line	= cache[line]
 lines	= cache[lines]
 pascal	= cache[pascal]

 puts pascal[(ARGV[0] || 15).to_i]

----------------------------------------------------------------

Refactoring gives us shorter, but less readable code:

----------------------------------------------------------------

 def c_lambda(&b)
   lambda{|f| h={} ; lambda{|*args| h[*args] ||= f[*args]}}[lambda(&b)]
 end

 fac	= c_lambda{|n| n < 2 ? 1 : (1..n).inject{|f, i| f * i}}
 tri	= c_lambda{|n, r| fac[n] / (fac[r] * fac[n-r])}
 size	= c_lambda{|r| tri[r-1, r / 2].to_s.size + 1}
 line	= c_lambda{|y, r| (0..y).map{|x| tri[y,x].to_s.center size[r]}}
 lines	= c_lambda{|r| (0...r).map{|y| line[y, r]}}
 pascal	= c_lambda{|r| lines[r].map{|l| l.join.center(size[r]*r).rstrip}}

 puts pascal[(ARGV[0] || 15).to_i]

----------------------------------------------------------------

gegroet,
Erik V. - http://www.erikveen.dds.nl/