Version 0 of memoizing

Updated 2004-01-23 10:26:54

I came up with this little proc while lamenting the confusing way that cache functions need to be called in mason [L1 ] - because perl has no way (that I'm aware of) for a subroutine to cause its caller to return, cache functions must be called as

  return if $m->cache_self();

In tcl this can be done much more elegantly. Just call this memoize proc at the beginning of another proc that is expensive to run and it will save the return value so it doesn't need to be recomputed.

  proc memoize {args} {
          global memo
          set cmd [info level -1]
          set d [info level]
          if {$d > 2} {
            set u2 [info level -2]
            if {[lindex $u2 0] == "memoize"} {
                    return
            }
          }
          if {[info exists memo($cmd)]} {
                  set val $memo($cmd)
          } else {
                  set val [eval $cmd]
                  set memo($cmd) $val
          }
          return -code return $val
  }

A classic use of this is the recursive fibonacci function:

  proc fibonacci {x} {
          if {$x <= 1} {return 1}
          return [expr [fibonacci [expr $x - 1]] + [fibonacci [expr $x - 2]]]
  }

Because this recomputes all lower values for every number, the performance is O(2^n)

  proc fibonacci-memo {x} {
          memoize
          if {$x <= 1} {return 1}
          return [expr [fibonacci-memo [expr $x - 1]] + [fibonacci-memo [expr $x
 - 2]]]
  }

By saving values that have already been computed by simply calling memoize, the performance becomes O(n)