纯功能相当于weakhashmap?
弱哈希表如 Java 的弱哈希映射 使用弱引用,用于跟踪垃圾收集器对无法访问的键的收集,并从集合中删除与该键的绑定。弱哈希表通常用于实现从图中的一个顶点或边到另一顶点或边的间接寻址,因为它们允许垃圾收集器收集图中无法到达的部分。
是否存在与此数据结构等价的纯功能?如果没有,如何创建一个?
这似乎是一个有趣的挑战。内部实现不可能是纯粹的,因为它必须收集(即变异)数据结构以删除无法访问的部分,但我相信它可以向用户呈现一个纯粹的界面,用户永远无法观察到杂质,因为它们只影响部分数据根据定义,用户无法再访问的结构。
Weak hash tables like Java's weak hash map use weak references to track the collection of unreachable keys by the garbage collector and remove bindings with that key from the collection. Weak hash tables are typically used to implement indirections from one vertex or edge in a graph to another because they allow the garbage collector to collect unreachable portions of the graph.
Is there a purely functional equivalent of this data structure? If not, how might one be created?
This seems like an interesting challenge. The internal implementation cannot be pure because it must collect (i.e. mutate) the data structure in order to remove unreachable parts but I believe it could present a pure interface to the user, who could never observe the impurities because they only affect portions of the data structure that the user can, by definition, no longer reach.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个有趣的概念。 “纯功能”设置中的一个主要复杂性是对象身份通常在“纯功能”意义上是不可观察的。 IE,如果我复制一个对象或创建一个新的相同对象,在 Java 中,预计克隆不是原始对象。但在功能设置中,预计新的在语义上与旧的相同,即使垃圾收集器会以不同的方式对待它。
因此,如果我们允许对象身份成为语义的一部分,那就是合理的,否则可能不是。在后一种情况下,即使可以找到黑客攻击(我想到了一个,如下所述),您也可能会遇到语言实现到处与您对抗的情况,因为它会做各种各样的事情来利用这一事实该对象身份不应该是可观察的。
我想到的一个“技巧”是使用构造上唯一的值作为键,这样在大多数情况下,值相等将与引用相等一致。例如,我有一个在 Haskell 中个人使用的库,其界面如下:
像您描述的哈希映射可能主要使用这些作为键,但即使在这里我也能想到一种可能会破坏的方法:假设用户将密钥存储在某些数据结构的严格字段中,并启用编译器的“unbox-strict-fields”优化。如果“Uniq”只是机器整数的新类型包装器,则可能不再有 GC 可以指向并说“这就是关键”的任何对象;因此,当用户打开钥匙并使用它时,地图可能已经忘记了它。 (编辑:这个特定的例子显然可以解决;让 Uniq 的实现成为不能像那样拆箱的东西;重点是它很棘手,因为编译器试图在很多方面提供帮助,而我们可能不会期待)
TL;DR:我不会说它不能完成,但我怀疑在很多情况下“优化”要么会被弱哈希映射实现破坏,要么被弱哈希映射实现破坏,除非对象标识被赋予一流的可观察值地位。
That's an interesting concept. One major complication in a "purely functional" setting would be that object identity is not normally observable in a "purely functional" sense. I.E., if I copy an object or create a new identical one, in Java it's expected that the clone is not the original. But in a functional setting, it is expected that the new one be semantically identical to the old one, even though the garbage collector will treat it differently.
So, if we allow object identity to be a part of the semantics, it would be sound, otherwise probably not. In the latter case, even if a hack could be found (I thought of one, described below), you're likely to have the language implementation fighting you all over the place because it's going to do all sorts of things to exploit the fact that object identity is not supposed to be observable.
One 'hack' that popped into my mind would be to use unique-by-construction values as keys, so that for the most part value equality will coincide with reference equality. For example, I have a library I use personally in Haskell with the following in its interface:
A hash map like you describe would probably mostly-work with these as key, but even here I can think of a way it might break: Suppose a user stores a key in a strict field of some data structure, with the compiler's "unbox-strict-fields" optimization enabled. If 'Uniq' is just a newtype wrapper to a machine integer, there may no longer be any object to which the GC can point and say "that's the key"; so when the user goes and unpacks his key to use it, the map may have forgotten about it already. (Edit: This particular example can obviously be worked around; make Uniq's implementation be something that can't be unboxed like that; the point is just that it's tricky precisely because the compiler is trying to be helpful in a lot of ways we might not expect)
TL;DR: I wouldn't say it can't be done, but I suspect that in many cases "optimizations" will either break or be broken by a weak hash map implementation, unless object identity is given first-class observable status.
从用户的角度来看,纯功能性数据结构无法改变。因此,如果我从哈希映射中获取一个键,等待,然后再次获取相同的键,我必须获得相同的值。我可以握住钥匙,这样它们就不会消失。
唯一可行的方法是 API 为我提供下一代,并且在发布对容器过去版本的所有引用之前不会收集这些值。数据结构的用户预计会定期要求新一代释放弱持有的值。
编辑(基于评论):我理解您想要的行为,但是您无法使用释放对象的地图通过此测试:
我建议此测试可以通过
Purely functional data-structures can't change from the user perspective. So, if I get a key from a hash-map, wait, and then get the same key again, I have to get the same value. I can hold onto keys, so they can't disappear.
The only way it could work is if the API gives me the next generation and the values aren't collected until all references to the past versions of the container are released. Users of the data-structure are expected to periodically ask for new generations to release weakly held values.
EDIT (based on comment): I understand the behavior you want, but you can't pass this test with a map that releases objects:
I am suggesting that this test could pass