Scheme中set!重定义fib为memoize结果与define新变量绑定的行为差异
问题成因分析
核心差异来源:递归调用的绑定对象不同
你定义的原始递归斐波那契函数内部,递归调用依赖的是fib这个符号的运行时绑定,两种写法对fib符号的修改行为不同,最终导致缓存生效范围不一样。
情况1:(set! fib (memoize 'memoize fib))
执行这行代码时的流程:
- 先取出当前
fib绑定的原始递归斐波那契函数,作为参数传给memoize memoize返回一个带独立缓存的包装函数set!会修改fib这个符号的绑定,让它指向新生成的带缓存的包装函数
当你调用(fib 3)时:
- 包装函数先查缓存,未命中则调用传入的原始fib计算3
- 原始fib内部递归调用的
fib,此时已经被重绑定到了带缓存的包装函数,每一步递归的(fib 2)、(fib 1)都会先走包装函数的缓存逻辑,计算完的结果会全部存入缓存 - 因此第一次调用会打印所有层级的计算日志,第二次调用
(fib 3)直接命中缓存无日志,后续调用(fib 2)也会直接命中缓存,不会重新计算。
情况2:(define mm (memoize 'memoize fib))
执行这行代码时的流程:
- 同样取出当前
fib绑定的原始递归函数传给memoize,生成带缓存的包装函数 - 仅将这个包装函数绑定到新符号
mm上,原始的fib符号绑定没有发生任何修改,仍然指向无缓存的原始递归函数
当你调用(mm 3)时:
mm的包装函数先查缓存,未命中则调用传入的原始fib计算3- 原始fib内部递归调用的仍然是绑定在
fib上的无缓存原始函数,所有递归的(fib 2)、(fib 1)都不会走mm的包装逻辑,计算结果也不会存入mm的缓存,只有最顶层的3的计算结果会被mm缓存 - 因此第二次调用
(mm 3)可以命中顶层缓存无日志,但调用(mm 2)时,mm的缓存中没有2的记录,会重新触发原始fib的计算,打印新的日志。
内容的提问来源于stack exchange,提问作者ili
相关产品推荐
相关产品推荐

