来自 Tcl wiki 的记忆过程的实现细节

Implementation details of memoizing procedure from Tcl wiki

我目前正在尝试了解 Tcl wiki several variants 中所示的以下记忆过程的实现细节:

proc memoize {} {
    global memo
    set cmd [info level -1]
    if {[info level] > 2 && [lindex [info level -2] 0] eq "memoize"} return
    if {![info exists memo($cmd)]} {set memo($cmd) [eval $cmd]}
    return -code return $memo($cmd)
}

他们所有人的共同点是(据我了解)他们将祖父母命令的第一个字lindex [info level -2] 0)与字面意思是这个记忆过程的名称(在本例中,"memoize")。

将此更改为比较 祖父命令此命令,换句话说,更改 [lindex [info level -2] 0] eq "memoize"[info level -2] eq [info level 0]?

没有明显的缺点,除非你中途绕过重命名命令,这确实非常脆弱(所以不要那样做)。最终,代码试图检测我们在哪里:

foo ab cd ef                 <--- A
   memoize                   <--- B
      foo ab cd ef           <--- C
         memoize             <--- D

当它发现堆栈配置时,它 returns 以便 D 什么都不做,C returns 实际计算值,B缓存该值,然后 A 可以在将来 return 它而无需计算它。这一切都相当复杂和骇人听闻;我更喜欢让函数正确地知道缓存内容。

它在其他几个关键方面也很脆弱,例如无法使用 upvar 或对自身进行递归调用的记忆函数。该 wiki 页面上的其他一些选项没有这个弱点。通过不检查 info level -2 结果的第一个单词,而是检查所描述的整个模式是否是存在(即 info level -1 是否也与 info level -3 相同,以及是否存在 info level -3)。