This really simple procedure is intended for long-running calculations:
array set delayed {} proc calcOnlyOnce args { set args1 [concat [ uplevel 1 namespace origin [lindex $args 0]] [lrange $args 1 end]] variable delayed if {[info exists delayed($args1)]} then { set delayed($args1) } else { set delayed($args1) [uplevel 1 $args] } }
Example usage -- this proc is slow:
proc fib n { if {$n <= 1} then { return 1 } else { set n1 [expr {$n-1}] set n2 [expr {$n-2}] expr {[fib $n1] + [fib $n2]} } }
Now test:
% time {calcOnlyOnce fib 25} 1 246325 microseconds per iteration % time {calcOnlyOnce fib 25} 1 39 microseconds per iteration %
The second call on same procedure was faster due to the fact that it was not re-calculated but "remembered" instead.
AM 2007-08-17: This is known as "memoization" - there are several Wiki pages on the subject.
wdb: Thanks for the hint ... before writing this page, I searched "delayed", "freeze" etc. Memoizing ... ok, I've learned a new word!