Hash 程序解释过程中高效的增量哈希计算

Hash 程序解释过程中高效的增量哈希计算,hash,lisp,scheme,interpreter,memoization,Hash,Lisp,Scheme,Interpreter,Memoization,我想写一个递归记忆方案解释器。在求值过程中的任何时候,解释器都应该能够检测到它何时接收到它以前看到的一对表达式和环境作为参数 对eval和apply的简单记忆效率低下。它需要在每次调用eval/apply时在哈希表中查找参数,这需要在哈希表匹配上遍历整个(可能较大)参数 例如,假设解释器评估程序 (car (list A)) 其中A计算为一个大对象。当解释器评估应用程序(列表A)时,它首先分别评估list和A。在将list应用于A之前,它会在其哈希表中查找以前是否见过此应用程序,遍历整个A对象

我想写一个递归记忆方案解释器。在求值过程中的任何时候,解释器都应该能够检测到它何时接收到它以前看到的一对表达式和环境作为参数

eval
apply
的简单记忆效率低下
。它需要在每次调用
eval
/
apply
时在哈希表中查找参数,这需要在哈希表匹配上遍历整个(可能较大)参数

例如,假设解释器评估程序

(car (list A))
其中A计算为一个大对象。当解释器评估应用程序
(列表A)
时,它首先分别评估
list
A
。在将
list
应用于
A
之前,它会在其哈希表中查找以前是否见过此应用程序,遍历整个
A
对象以计算哈希。稍后,当记忆解释器将
car
应用于包含A的列表时,它会计算该列表的哈希值,该哈希值再次涉及遍历整个A对象

相反,我想构建一个解释器,以增量方式构建近似唯一的散列,尽可能避免重新计算,并保证冲突不太可能发生

例如,可以使用解释器值的MD5递归扩展解释器操作的每个对象,或者,如果是复合对象,则使用其组件哈希的MD5递归扩展解释器操作的每个对象。一个环境可能存储其每个变量/值项的散列,并且环境的散列可能作为单个散列的函数进行计算。然后,如果环境中的一个条目发生更改,则不必重新访问整个环境来计算环境的新哈希。相反,只需要重新计算更改的变量/值对的哈希,并且需要更新条目哈希集的全局哈希


是否存在增量构建近似唯一散列的相关工作,特别是在递归记忆和/或程序计算的上下文中?

请注意,如果表达式是不可变的(不允许自修改代码),则可以对其使用EQ等式。如果环境是不可变的,您可以同样对待它们。EQ相等速度很快,因为您只是将机器指针中的位作为散列

问题是赋值会改变环境,导致表达式值改变。如果他们被允许,你将如何处理这一问题

一种方法是记录在词法范围中包含破坏性代码的环境,并以某种方式对其进行注释,以便评估者能够识别此类“污染环境”,而不是为其进行缓存


顺便说一句,您显然需要语义较弱的哈希表,这样任何成为垃圾的对象都不会堆积在内存中。

好的方面,谢谢!为了澄清我的问题:如果一个对象在评估过程中在多个位置独立创建,我也想抓住这一点,这排除了EQ。这可能排除了对象上的EQ,但不排除在构建过程中应用的浅成员对成员EQ。也就是说,在这个浅等分下可能有一张物体的地图。例如,对于cons,浅相等意味着CAR-s是EQ,CDR-s是EQ。如果机器发现自己将cons两个值,其中已经存在一个单元格,它可以返回该单元格。这一点很重要,因为您不希望一直遍历大型对象。(对于大向量仍然存在一个问题。)整洁。作为参考,“hash consing”是该技术的名称。(当我仔细考虑将这种方法应用于问题中概述的设置时,我会将你的答案标记为正确的。)《红龙书》(编者:原则、技术和工具,Aho,Sethi,Ullman,1988)也在5.2中,在“表达式的有向无环图”标题下的一些段落中描述了类似的内容。想法是一样的:对于给定的操作符和离开,找到一个具有相同操作符的节点并离开并重用它。但是这样的解释器如何计算
(eq?(list)(list))
?如果您将
eq?
的含义理解为“两个对象存储在相同的内存地址吗?”,那么它应该返回
true
。对不起。。。我的意思是
(eq?(list'A)(list'A))
。表单
(列表…
不是列表对象,而是列表生成器。列表对象将是
”(A)
。我不理解您的调用示例是否可以节省时间,除非您当然是在讨论更高层次的推理,即如果其他两个表达式没有副作用,则组合
(car(list))
可以优化为
,而不改变语义。通常,
list
调用每次都返回不同的结果。如果您想引入可记忆的“纯”函数的概念,则
list
不是其中之一。