【问题标题】:Complex data structures in Haskell - how do they work?Haskell 中的复杂数据结构——它们是如何工作的?
【发布时间】:2011-01-04 18:57:14
【问题描述】:

我发现,Haskell 中的变量是不可变的(因此,它们并不是真正的“变量”)。

在这种情况下,如果我们有一个复杂的大数据结构,比如一棵红黑树,我们应该如何实现真正改变数据结构的操作?

每次插入或删除元素时创建树的副本?

【问题讨论】:

  • “因此,它们并不是真正的‘变量’”——它们确实是。例如,当一位数学家说“让 G 成为群 (S,*),其中 ...”时,G 是变量,即使它永远不会改变。这与 Haskell 中的原理相同。
  • 您当然提出了一个有趣的观点,确实结构发生了一些变化以适应不变性而不牺牲性能。将您的结构想象成一个有向图(其中从 A 到 B 的边意味着 A 持有对 B 的引用/索引),然后如果您希望更改 B,则需要复制可访问 B 的任何顶点并更新其引用.例如,我仍然没有找到如何在 Haskell 中表示跳过列表 :)

标签: data-structures haskell immutability


【解决方案1】:

是的,解决方案是返回一个表示修改后值的新数据结构,但是不需要复制示例的整个结构(红黑树),因为您可以只复制路径上的节点插入节点的根。这允许插入操作与命令式版本具有相同的复杂性。

Chris Okasaki 的 Purely functional data structures 包含许多不可变数据结构的实现 - 这本书是他的博士论文的修改版,您可以找到 here

【讨论】:

【解决方案2】:

您对复制的直觉正是您应该思考的正确方向。然而,“复制”是由 Haskell 运行时智能实现的。例如,给定

data Tree = Empty | Branch Tree Integer Tree

你可以实现一个函数来替换左分支:

replaceLeft :: Tree -> Tree -> Tree
replaceLeft (Branch _ i r) newLeft = Branch newLeft i r

结果不是您创建了新树的完整副本,因为这不是必需的。值i 和树rnewLeft 没有改变,所以我们不必将它们的内容复制到新的内存中。

创建的新Branch(这是此示例中唯一真正的分配:创建用于保存Integer 上的左/右树的结构)仍然引用旧分支中完全相同的值,无需复制!

由于数据结构是不可变的,因此这样做没有害处。

【讨论】:

  • 我喜欢对不变性的关注:正是不变性让我们能够实现这种共享。
猜你喜欢
  • 2014-09-29
  • 1970-01-01
  • 1970-01-01
  • 2022-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
相关资源
最近更新 更多