在我最初尝试创建不相交集数据结构时,我创建了一个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
对于父字段,请参见我的另一个问题 https://stackoverflow.com/questions/18076891/do-i-need-to-take-explicit-actions-to-facilitate-sharing-with-persistent-data-st.)
不,你所要求的在 Haskell 世界中被称为参考身份:对于某种类型的两个值,您可以检查它们在内存中是否是相同的值,或者两个恰好具有完全相同属性的单独值。
对于您的示例,您可以问自己是否认为以下两个值相同:
pl1 :: Point Int
pl1 = Point 0 (Point 0 pl1 1) 1
pl2 :: Point Int
pl2 = Point 0 pl2 1
Haskell 认为这两个值完全相等。 IE。哈斯克尔确实not支持参考身份。原因之一是它会违反 Haskell 支持的其他功能。例如,在 Haskell 中,我们总是可以用函数的实现替换对函数的引用,而不改变含义(等式推理)。例如,如果我们执行pl2
: Point 0 pl2 1
并替换pl2
根据它的定义,我们得到Point 0 (Point 0 pl2 1) 1
, 制作pl2
的定义等价于pl1
的。这表明 Haskell 无法让你观察到之间的差异pl1
and pl2
不违反等式推理所隐含的属性。
您可以使用不安全的功能,例如unsafePerformIO
(如上所述)解决 Haskell 中缺乏引用标识的问题,但是您应该知道,您正在破坏 Haskell 的核心原则,并且当 GHC 开始优化(例如内联)您的代码时,您可能会观察到奇怪的错误。最好使用不同的数据表示形式,例如你提到的那个使用Maybe Point
value.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)