Haskell 中的异构引用相等性

Heterogeneous reference equality in Haskell

在 GHC 中,IORefSTRef 的相等实例基于以下原始操作:

sameMutVar# :: MutVar# s a -> MutVar# s a -> Int#

我希望能够计算异构引用相等性,

sameReference :: IORef a -> IORef b -> Bool

(或类似的 STRefs 具有可能不同的类型)。是否可以只使用 unsafeCoerce 来检查引用相等性? sameMutVar# 没有给出异构类型签名是有原因的吗?

编辑:为了添加一些上下文,我想要这种异类指针相等性,因为我想使用相等性方法从 IORef 的列表中删除特定的 IORef a,其类型存在量化超过。

写起来绝对安全

sameReference :: IORef a -> IORef b -> Bool
sameReference = unsafeCoerce ((==) :: IORef a -> IORef a -> Bool)

primop 被赋予类型是完全合理的

sameMutVar# :: MutVar# s a -> MutVar# s b -> Int#

但设计者显然认为在不同类型的引用上使用该函数比其他方式更容易出错。

不能安全地得出结论sameReference (r1 :: IORef a) (r2 :: IORef b) = True意味着ab是相同的。假设你有

sameRefSameType :: IORef a -> IORef b -> Maybe (a :~: b)

那你就可以轻松写

oops :: Coercible a b => IORef a -> a :~: b
oops r = fromJust (sameRefSameType r (coerce r))

产生任何两个可强制类型相等的虚假证据。您应该能够弄清楚如何使用 GADT 从那里到达 mkUC :: IO (a -> b).

相信

是安全的
sameRefCoercibleTypes :: IORef a -> IORef b -> Maybe (Coercion a b)

既然 Daniel Wagner 提到了稳定的名字,我应该指出,在这种情况下,那些人的情况更糟。我需要先了解一些背景知识。假设你写

f :: Either x Int -> Either x Bool
f (Left x) = Left x
f (Right _) = Right False

在第一种情况下,分配一个新的 Left 构造函数只是为了改变类型是一种耻辱。所以 GHC 有一个低级优化(在核心到核心优化管道之后)试图把它变成(本质上)

f p@(Left x) = unsafeCoerce p
f (Right _) = Right False

这意味着您可以有 m :: Either x an :: Either x b,其中 mn 指的是同一个堆对象,尽管 ab 具有完全不相关的类型。如果您为 m 创建一个稳定名称并为 n 创建一个稳定名称,那么这些稳定名称将比较相等!如果你存入甚至高达

sameSNCoercibleTypes
  :: StableName a
  -> StableName b
  -> Maybe (Coercion a b)

然后您可以使用 mn 到 "prove" Coercible (Either x a) (Either x b),您可以从中将任何 a 转换为任何 b。这有点微妙,但因为它是可能的,否则假设是相当不安全的。