是否可以将所有类型检查出现的 `coerce` 安全地替换为 `unsafeCoerce`?

Can all typechecking occurrences of `coerce` safely be replaced with `unsafeCoerce`?

我相信以下内容与 Set.mapMonotonic coerce 一样安全。即,如果 ab 有不同的 Ord 实例,我将破坏 Set 不变量:

coerceSet :: Coercible a b=> Set.Set a -> Set.Set b
coerceSet = unsafeCoerce

对吗?

编辑Set的相关功能问题:https://github.com/haskell/containers/issues/308

应该是安全的。

有效的 coerce @a @b 始终可以替换为有效的 unsafeCoerce @a @b。为什么?因为,在核心级别,它们是相同的函数,coerce(只是 returns 它的输入,如 id)。问题是 coerce 作为参数,证明被强制转换的两个事物具有相同的表示。对于普通的 coerce,这个证明是一个实际的证明,但是对于 unsafeCoerce,这个证明只是一个表示 "trust me" 的标记。此证明作为类型参数传递,因此,通过类型擦除,对程序的行为没有影响。因此 unsafeCoercecoerce 在可能的情况下是等价的。

现在,Set 的故事还没有结束,因为 coerceSet 上不起作用。为什么?让我们看看它的定义。

data Set a = Bin !Size !a !(Set a) !(Set a) | Tip

从这个定义中,我们看到 a 没有出现在任何类型等式等中。这意味着我们在 Set 处具有表示等式的同余:如果 a ~#R b(如果ab 具有相同的表示形式——~#R 未装箱 Coercible),然后是 Set a ~#R Set b。因此,仅根据 Set 的定义,coerce 应该 Set 上工作,因此您的 unsafeCoerce 应该是安全的。 containers 库必须使用特定的

type role Set nominal

向世界隐藏这一事实,人为地禁用 coerce。但是,您永远不能禁用 unsafeCoerce,并且重申,unsafeCoerce(在此上下文中)是安全的。

(请注意 unsafeCoercecoerce 具有相同的类型!请参阅@dfeuer 的回答以了解 "overzealous" 类型推断将所有内容都扭曲的情况示例形状。)

是的,这在典型的现实情况下应该是安全的。但是, 有可能提出人为的例子,而事实并非如此。这是一个使用默认设置的。我想也许可以使用重叠实例或其他古怪的功能来做类似的事情,但我不知道。

{-# language GADTs, TypeOperators, ExistentialQuantification #-}

import Data.Coerce
import Unsafe.Coerce
import Data.Type.Equality

data Buh a = Buh (a :~: Rational) a

data Bah = forall a. Bah (a :~: Rational) a

instance Show Bah where
  show (Bah Refl x) = show x

goo :: Rational -> Bah
goo x = case coerce p of
          Buh pf m ->
            let _q = truncate m
            in Bah pf 12
  where
    p = Buh Refl x

如果你打电话给goo,一切都会好起来的。如果您将 coerce 替换为 unsafeCoerce,调用 goo 将出现段错误或做其他不好的事情。