是否可以将所有类型检查出现的 `coerce` 安全地替换为 `unsafeCoerce`?
Can all typechecking occurrences of `coerce` safely be replaced with `unsafeCoerce`?
我相信以下内容与 Set.mapMonotonic coerce
一样安全。即,如果 a
或 b
有不同的 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" 的标记。此证明作为类型参数传递,因此,通过类型擦除,对程序的行为没有影响。因此 unsafeCoerce
和 coerce
在可能的情况下是等价的。
现在,Set
的故事还没有结束,因为 coerce
在 Set
上不起作用。为什么?让我们看看它的定义。
data Set a = Bin !Size !a !(Set a) !(Set a) | Tip
从这个定义中,我们看到 a
没有出现在任何类型等式等中。这意味着我们在 Set
处具有表示等式的同余:如果 a ~#R b
(如果a
与 b
具有相同的表示形式——~#R
未装箱 Coercible
),然后是 Set a ~#R Set b
。因此,仅根据 Set
的定义,coerce
应该 在 Set
上工作,因此您的 unsafeCoerce
应该是安全的。 containers
库必须使用特定的
type role Set nominal
向世界隐藏这一事实,人为地禁用 coerce
。但是,您永远不能禁用 unsafeCoerce
,并且重申,unsafeCoerce
(在此上下文中)是安全的。
(请注意 unsafeCoerce
和 coerce
具有相同的类型!请参阅@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
将出现段错误或做其他不好的事情。
我相信以下内容与 Set.mapMonotonic coerce
一样安全。即,如果 a
或 b
有不同的 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" 的标记。此证明作为类型参数传递,因此,通过类型擦除,对程序的行为没有影响。因此 unsafeCoerce
和 coerce
在可能的情况下是等价的。
现在,Set
的故事还没有结束,因为 coerce
在 Set
上不起作用。为什么?让我们看看它的定义。
data Set a = Bin !Size !a !(Set a) !(Set a) | Tip
从这个定义中,我们看到 a
没有出现在任何类型等式等中。这意味着我们在 Set
处具有表示等式的同余:如果 a ~#R b
(如果a
与 b
具有相同的表示形式——~#R
未装箱 Coercible
),然后是 Set a ~#R Set b
。因此,仅根据 Set
的定义,coerce
应该 在 Set
上工作,因此您的 unsafeCoerce
应该是安全的。 containers
库必须使用特定的
type role Set nominal
向世界隐藏这一事实,人为地禁用 coerce
。但是,您永远不能禁用 unsafeCoerce
,并且重申,unsafeCoerce
(在此上下文中)是安全的。
(请注意 unsafeCoerce
和 coerce
具有相同的类型!请参阅@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
将出现段错误或做其他不好的事情。