在GHC中,IORef
和STRef
的相等实例基于以下原始运算:
sameMutVar# :: MutVar# s a -> MutVar# s a -> Int#
我希望能够计算出异构的引用相等性,
sameReference :: IORef a -> IORef b -> Bool
(或类似地用于STRef
,其类型可能不同)。可以仅使用unsafeCoerce
来检查引用相等性吗?是否没有为sameMutVar#
提供异类签名?
编辑:要添加一些上下文,我想拥有这种异构的指针相等性,因为我想使用相等性方法从类型为存在的IORef a
列表中删除特定的IORef
量化结束。
答案 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
意味着a
和b
是相同的。假设你有
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 a
和n :: Either x b
,其中m
和n
引用相同的堆对象,尽管a
和b
具有完全无关的类型。如果您为m
创建一个稳定名称,并为n
创建一个稳定名称,那么这些稳定名称将比较相等!如果您假设最多
sameSNCoercibleTypes
:: StableName a
-> StableName b
-> Maybe (Coercion a b)
然后,您可以使用m
和n
来“证明” Coercible (Either x a) (Either x b)
,从中可以将任何a
转换为任何b
。有点微妙,但是既然有可能,那么假设否则是相当不安全的。