【问题标题】:Self-reference in data structure – Checking for equality数据结构中的自引用——检查相等性
【发布时间】:2013-08-06 10:20:21
【问题描述】:

在我最初尝试创建一个不相交的集合数据结构时,我创建了一个Point 数据类型,其中parent 指向另一个Point

data Point a = Point
  { _value  :: a
  , _parent :: Point a
  , _rank   :: Int
  }

为了创建一个单例集,创建了一个Point,并将其自身作为其父级(我相信这被称为打结):

makeSet' :: a -> Point a
makeSet' x = let p = Point x p 0 in p

现在,当我想写findSet(即跟随父指针,直到找到其父为自身的Point)时,我遇到了一个问题:是否可以检查是否是这种情况?一个幼稚的Eq 实例当然会无限循环——但这个检查在概念上是否可以编写?

(我最终使用Maybe Point 作为父字段,请参阅my other question。)

【问题讨论】:

  • 从概念上讲,什么时候 2 点是同一件事?当他们的 _value 和 _rank 相同时?

标签: haskell data-structures tying-the-knot


【解决方案1】:

不,您所要求的在 Haskell 世界中被称为 引用身份:对于某种类型的两个值,您可以检查它们在内存中是否是相同的值或恰好具有完全相同属性的两个单独的值。

对于您的示例,您可以问自己是否会认为以下两个值相同:

pl1 :: Point Int
pl1 = Point 0 (Point 0 pl1 1) 1

pl2 :: Point Int
pl2 = Point 0 pl2 1

Haskell 认为这两个值完全相等。 IE。 Haskell 确实支持引用身份。原因之一是它会违反 Haskell 支持的其他功能。例如,在 Haskell 中,我们总是可以用函数的实现替换对函数的引用,而不会改变含义(等式推理)。例如,如果我们实现pl2: Point 0 pl2 1 并用它的定义替换pl2,我们得到Point 0 (Point 0 pl2 1) 1,使得pl2 的定义等同于pl1 的定义。这表明 Haskell 不能让您观察 pl1pl2 之间的差异而不违反等式推理所隐含的属性。

您可以使用 unsafePerformIO 之类的不安全功能(如上所述)来解决 Haskell 中缺乏引用身份的问题,但您应该知道您正在破坏 Haskell 的核心原则,并且您可能会在 GHC 启动时观察到奇怪的错误优化(例如内联)您的代码。最好使用不同的数据表示,例如你提到的那个使用Maybe Point 值。

【讨论】:

    【解决方案2】:

    您可以尝试使用StableName(或StablePtr)和unsafePerformIO 来执行此操作,但在这种情况下,这似乎比Maybe Point 更糟糕。

    【讨论】:

      【解决方案3】:

      为了观察到您最感兴趣的效果(指针相等而不是值相等),您很可能希望在 ST monad 中编写算法。 ST monad 可以被认为有点像“本地不纯 IO,全局纯 API”,但根据 Union Find 的性质,您可能必须将整个查找过程浸入代码的不纯部分。

      幸运的是,monad 仍然可以很好地包含这种杂质。

      There is also already an implementation of Union Find in Haskell 使用三种方法来实现您正在寻找的身份类型:使用 IO monad、使用 IntSets 和使用 ST monad。

      【讨论】:

        【解决方案4】:

        在 Haskell 中,数据是不可变的(IO aIORef aST aSTRef a 除外)并且数据是函数。 所以,任何数据都是“单例”

        当你输入时

        data C = C {a, b :: Int}
        changeCa :: C -> Int -> C
        changeCa c newa = c {a = newa}
        

        您不会更改变量,而是破坏旧数据并创建新数据。 您可以尝试使用链接和指针,但它既无用又复杂

        最后,

        data Point a = Point {p :: Point a}
        

        是一个类似列表的无限数据 = Point { p=Point { p=Point { p=Point { ....

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-26
          • 1970-01-01
          • 1970-01-01
          • 2015-11-23
          相关资源
          最近更新 更多