パッケージからのData.Reflection
のGHC実装では、GHCが辞書パスを使用してタイプメーターをコンパイルする方法を利用するunsafeCoerce
というトリックを使用します。実装は短いですので、私はここにその全体でそれを再現することができますData.Reflectionのトリックは、基底クラスの代わりにタイプファミリーを使用して実装できますか?
class Reifies s a | s -> a where
reflect :: proxy s -> a
newtype Magic a r = Magic (forall (s :: *). Reifies s a => Proxy s -> r)
reify :: forall a r. a -> (forall (s :: *). Reifies s a => Proxy s -> r) -> r
reify a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
これは、それをバックに反映、タイプレベルの値を具体化することを可能にする:
ghci> reify (42 :: Integer) (\p -> reflect p) :: Integer
42
私は興味がありましたこのテクニックを使用する際には、私の目的上、機能的な依存関係ではなくReifies
の型ファミリを使用するのが便利だと思ったので、通常の変換を使用して実装を書き直そうとしました。
しかし、残念ながら、これはもう機能しません!私はGHCの理由を理解するためにどのように動作するかを十分に慣れていないよ、しかし
ghci> reify (42 :: Integer) (\p -> reflect p) :: Integer
2199023255808
:これはunsafeCoerce
トリックを破るために十分有意にコンパイルを変更します。関数従属の代わりに関連型を使用してData.Reflection
を実装することは可能ですか?もしそうなら、何を変える必要がありますか?そうでない場合は、どうしてですか?
、少なくともコアレベルで。型平等の証人がどのように働くかに関する情報がありますか?平等の目撃者の代わりに何か他のものを(不安定に)提供することはできますか?私のコードを 'unsafeCoerce(Magic k :: Magic a r)(const a)()Proxy()Proxy'に少し変更すると動作しますが、常にうまくいかないかもしれません。 –
@AlexisKing、それは私が答えを知らない良い質問です。 – dfeuer
@AlexisKing、もう一つの選択肢(私は思う)は、 'reflect''が' a〜Reflects s'という証拠を与えるGADTを返すようにするかもしれないと思います。私はそれをまだ遂行していません。 – dfeuer