web-dev-qa-db-ja.com

`coerce`のすべての型チェックオカレンスを` unsafeCoerce`で安全に置き換えることができますか?

以下はSet.mapMonotonic coerceと同じくらい安全だと思います。つまり、Setまたはaに異なるbインスタンスがある場合、起こりうる最悪の事態はOrd不変式を壊すことです。

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

あれは正しいですか?

[〜#〜] edit [〜#〜]Setに関連する機能の問題: https:// github .com/haskell/containers/issues/308

22
jberryman

これすべき安全です。

有効なcoerce @a @bは、常に有効なunsafeCoerce @a @bで置き換えることができます。どうして?コアレベルでは、これらはcoerceidのように入力を返すだけ)の同じ関数だからです。 coerceは、強制される2つのものが同じ表現であることの証明を引数として取るということです。通常のcoerceの場合、この証明は実際の証明ですが、unsafeCoerceの場合、この証明は、「信頼してください」というトークンにすぎません。この証明は型引数として渡されるため、型消去によってプログラムの動作に影響を与えることはありません。したがって、unsafeCoercecoerceは、両方が可能な場合は常に同等です。

Setcoerceでは機能しないため、これでSetの話は終わりではありません。どうして?その定義をのぞいてみましょう。

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

この定義から、aはどの型の等式の内部にも現れないことがわかります。これは、Setで表現型の等値の合同があることを意味します:if a ~#R b(if abと同じ表現を持ち、~#Rはボックス化解除されたCoercible)であり、次にSet a ~#R Set bです。したがって、Setだけの定義から、coerceshouldSetを処理し、したがってunsafeCoerceすべき安全です。 containersライブラリは特定の

type role Set nominal

この事実を世界から隠すには、coerceを人為的に無効にします。ただし、unsafeCoerceを無効にすることはできません。繰り返しますが、unsafeCoerce(このコンテキストでは)は安全です。

unsafeCoercecoerceの型が同じになるように注意してください!「熱狂的」な型の推論がすべてを形から曲げる状況の例については、@ dfeuerの回答を参照してください。)

11
HTNW

はい、これは通常の現実的な状況では安全です。しかし、それはisであるが、そうでない場合の不自然な例を考え出すことは可能です。デフォルトを使用するものは次のとおりです。重複するインスタンスや他の奇抜な機能を使用して同様のことを実行できる可能性があると想像しますが、わかりません。

{-# 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を呼び出すと、すべてうまくいきます。 coerceunsafeCoerceに置き換えた場合、gooを呼び出すと、セグメンテーション違反が発生したり、他の問題が発生したりします。

5
dfeuer