Haskell中的异构引用相等

时间:2019-03-16 01:39:01

标签: haskell ghc

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

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

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

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

(或类似地用于STRef,其类型可能不同)。可以仅使用unsafeCoerce来检查引用相等性吗?是否没有为sameMutVar#提供异类签名?

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

1 个答案:

答案 0 :(得分:4)

写是绝对安全的

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来“证明” Coercible (Either x a) (Either x b),从中可以将任何a转换为任何b。有点微妙,但是既然有可能,那么假设否则是相当不安全的。