我想更好地了解例如实习生。 Data.Map。当我在Map中插入一个新的绑定时,由于数据的不变性,我得到一个与旧数据结构加上新绑定相同的新数据结构。
我想了解这是如何实现的。编译器是否最终通过复制整个数据结构来实现这一点。数以百万计的绑定?通常可以说可变数据结构/数组(例如Data.Judy)或命令式编程语言在这种情况下表现更好吗?在字典/键值存储方面,不可变数据是否有任何优势?
答案 0 :(得分:31)
Map
建立在树数据结构之上。基本上,构造了一个新的Map
值 ,但它几乎完全被指向旧结构的指针填充。由于Haskell中的值永远不会改变,因此这是一种安全且非常重要的优化,称为 sharing 。
这意味着您可以使用相同数据结构的许多相似版本,但只有不同树的分支将被重新存储;其余的只是指向分支原始副本的指针。当然,如果你丢弃旧的Map
,你所做的更改的分支将由垃圾收集器回收。
共享是不可变数据结构性能的关键。您可能会发现this Wikipedia article有帮助;它有一些启发性图表,显示修改后的数据如何通过共享来表示。
答案 1 :(得分:15)
没有。 The documentation for Data.Map.insert
表示插入需要 O(log n)时间。如果它必须复制整个结构,就不可能满足那个界限。
答案 2 :(得分:5)
Data.Map不会复制旧地图;它(懒惰地)分配O(log N)个新节点,这些节点指向(并因此共享)大部分旧地图。
由于“更新”地图不会破坏旧版本,因此这种数据结构可让您更自由地构建并发算法。