在《Lisp之国》的第329页,Conrad Barski通过以下示例代码解释了记忆化技术。
(let ((old-neighbors (symbol-function 'neighbors))
(previous (make-hash-table)))
(defun neighbors (pos)
(or (gethash pos previous)
(setf (gethash pos previous) (funcall old-neighbors pos)))))
这个想法很好:当我调用
neighbors
函数时,将结果保存到哈希表中,这样下次再调用neighbors
函数并使用相同的pos
值时,可以直接查找结果,而无需重新计算。所以我在想,通过编辑和重新编译源代码(书上第314页有),将函数
neighbors
重命名为old-neighbors
是否更容易。然后memoization示例就可以简化为:(let ((previous (make-hash-table)))
(defun neighbors (pos)
(or (gethash pos previous)
(setf (gethash pos previous) (funcall old-neighbors pos)))))
或者,事先将
previous
转换为全局变量*previous-neighbors*
,甚至可以转换成。(defun neighbors (pos)
(or (gethash pos *previous-neighbors*)
(setf (gethash pos *previous-neighbors*) (funcall old-neighbors pos))))
因此使闭包不再必要。
所以我的问题是:这样做的原因是什么?
我能想到的原因:
1.这是教学性的,展示了使用闭包(之前已经解释过)并提供了
symbol-function
的示例。2.即使在您无法或不允许更改
neighbors
的源代码的情况下,也可以使用这种技术。3.我可能漏掉了什么重要的东西。
(memoize 'foo) (foo 10)
而另一个则需要使用类似于以下内容进行调用(setq fast-foo (memoize 'foo)) (funcall fast-foo 10)
除此之外,还有其他区别吗?例如在比较时使用equal而不是eql? - Dominik Mokriš