语境
我发现在我有限的使用Common的经验中,像这样的代码并不少见
(setf (gethash key table)
(my-transformation (gethash key table)))在从setf可访问的位置读取数据时,对存储在那里的值执行一些计算,然后将其写入相同的位置。我不喜欢的是这个地方会被计算两次,但是这个地方会(希望!)两次都一样。如果位置计算很昂贵,我们所做的工作是我们需要做的工作的两倍。
问题
是否有可能消除双重计算的需要?也就是说,这是否可能(可取)?编写宏setf-inplace
(setf-inplace (gethash key table) #'my-transformation)在概念上等同于(暂时忽略了multiple-values的奇怪之处),但可能比原始代码快得多,最好不依赖于实现细节?
我知道在这种特殊情况下,我可能会把事情推到前面,因为gethash,但在我看来,其他setf功能的地方,比如(assoc key my-alist),可能不那么容易缓存--当然,除了通过像上面的setf-inplace这样的机制之外。
发布于 2014-02-25 08:30:31
(setf (gethash key table)
(my-transformation (gethash key table)))假设转换是1+。那么上面是
(setf (gethash key table)
(1+ (gethash key table)))在通用Lisp中有一个宏:
(incf (gethash key table))Clozure CL将其扩展到:
(LET* ((#:G69020 KEY)
(#:G69021 TABLE)
(#:G69022 1)
(#:G69019 (+ (GETHASH #:G69020 #:G69021) #:G69022)))
(DECLARE (TYPE BIT #:G69022) (TYPE T #:G69019))
(CCL::PUTHASH #:G69020 #:G69021 #:G69019))现在请记住,一个位置的setter是在编译时找到的,并且一个位置的setter操作与getter不同。设置者不仅通过更新某些内容,而且还可以执行任意的其他事情,例如设置事务、获取锁、.因此,获取和设置并不是相同的/相似的两次操作。
通用Lisp没有物理数据结构来表示一个位置。一个地方是一个抽象的想法,它结合了一个设置者和一个给定的吸气者。setter可以是任意复杂的代码。
那么,在上面的代码中,哪些计算是多余的?
您仍然会说,如何优化对原始案例的访问:
(incf (car (very-long-access-chain data)))你必须用手写字:
(let ((cons-cell (very-long-access-chain data)))
(incf (car cons-cell))这基本上就是Lisp所做的。见: CLHS 5.1.1.1对地点的次级形式的评估
https://stackoverflow.com/questions/22007962
复制相似问题