首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用setf避免冗余位置计算

用setf避免冗余位置计算
EN

Stack Overflow用户
提问于 2014-02-25 07:59:47
回答 1查看 158关注 0票数 5

语境

我发现在我有限的使用Common的经验中,像这样的代码并不少见

代码语言:javascript
复制
(setf (gethash key table)
      (my-transformation (gethash key table)))

在从setf可访问的位置读取数据时,对存储在那里的值执行一些计算,然后将其写入相同的位置。我不喜欢的是这个地方会被计算两次,但是这个地方会(希望!)两次都一样。如果位置计算很昂贵,我们所做的工作是我们需要做的工作的两倍。

问题

是否有可能消除双重计算的需要?也就是说,这是否可能(可取)?编写宏setf-inplace

代码语言:javascript
复制
(setf-inplace (gethash key table) #'my-transformation)

在概念上等同于(暂时忽略了multiple-values的奇怪之处),但可能比原始代码快得多,最好不依赖于实现细节?

我知道在这种特殊情况下,我可能会把事情推到前面,因为gethash,但在我看来,其他setf功能的地方,比如(assoc key my-alist),可能不那么容易缓存--当然,除了通过像上面的setf-inplace这样的机制之外。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-02-25 08:30:31

代码语言:javascript
复制
(setf (gethash key table)
      (my-transformation (gethash key table)))

假设转换是1+。那么上面是

代码语言:javascript
复制
(setf (gethash key table)
      (1+ (gethash key table)))

在通用Lisp中有一个宏:

代码语言:javascript
复制
(incf (gethash key table))

Clozure CL将其扩展到:

代码语言:javascript
复制
(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可以是任意复杂的代码。

那么,在上面的代码中,哪些计算是多余的?

您仍然会说,如何优化对原始案例的访问:

代码语言:javascript
复制
(incf (car (very-long-access-chain data)))

你必须用手写字:

代码语言:javascript
复制
(let ((cons-cell (very-long-access-chain data)))
  (incf (car cons-cell))

这基本上就是Lisp所做的。见: CLHS 5.1.1.1对地点的次级形式的评估

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22007962

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档