キー/値のマッピングを表すクラスを開発していて、基本的に次のような関数がありますalterF
。
class C t where
...
alterF :: Functor f =>
(Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t
残念ながら、これは壊れGeneralisedNewtypeDeriving
ます。場合によっては、これは合理的です。GeneralisedNewtypeDeriving
私が理解していることから、本質的にCoercibleと関数を使用しているからcoerce
です。Coercible
表現的に等しいタイプを表します。つまり、実行時に同じ表現を持つため、無料で変換できます。たとえば、次のようになります。
newtype T a = T a
我々は持っています:
Coercible a (T a)
Coercible (T a) a
しかし、私たちは(一般的に)持っていません:
Coercible (f a) (f (T a))
Coercible (f (T a)) (f a)
たとえば、GADTはこの表現の平等に違反します。しかし、f
それが機能するという価値観はたくさんあります。例えば:
Coercible (Maybe a) (Maybe (T a))
Coercible (Maybe (T a)) (Maybe a)
Coercible [a] [T a]
Coercible [T a] [a]
Coercible (Identity a) (Identity (T a))
Coercible (Identity (T a)) (Identity a)
このインスタンスは次のように記述できることも私には思い浮かびます。
Functor f => Coercible (f a) (f (T a))
Functor f => Coercible (f (T a)) (f a)
を使用するだけfmap
です。通常とは異なりcoerce
、これは実行時に無料ではありませんが、機能します。
したがって、10個の関数を持つクラスがあり、そのうち9個はで正常に機能しGeneralisedNewtypeDeriving
ます。を使用して機械的に解決できる、そうでない最後の1つだけがありfmap
ます。すべてのクラス関数のカスタムラッピング/アンラッピング実装を作成する必要がありますか、それとも問題のある関数のみの実装を作成するように要求する方法、またはGHCをfmap
その一部として使用するように誘導する方法はありGeneralisedNewtypeDeriving
ますか?
場合f
でFunctor
、あなたはそれのために、「表現ラッパー」を作ることができます
data Rep f a where
Rep :: (b -> a) -> f b -> Rep f a
これはf
、で表象的であることを除いて同型でありa
、名目上の分散に対する本質的に存在記号であるf
可能性があります。この構造にはたまたま派手な圏論の名前があると思いますが、それが何であるかは覚えていません。からf a
戻るにはRep f a
、f
のFunctor
フードを使用する必要があります。
このラッパーをメソッドで使用して、クラスが表現的に変化するようにすることができます。
alterFRep :: (Functor f)
=> (Maybe (Value t) -> Rep f (Maybe (Value t))) -> Key t -> t -> Rep f t
そして、との同型写像を使用して、実際の「メソッド」を通常の関数にしRep f
ます。インスタンス作成者にとって便利な方法を作成することもできます。
toAlterFRep ::
(forall f t. (Functor f) => (Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t)
-> (forall f t. (Functor f) => (Maybe (Value t) -> Rep f (Maybe (Value t))) -> Key t -> t -> Rep f t)
そのため、一体何であるかを心配する必要はありません。通常どおりにRep
実装alterF
して使用toAlterFRep
するだけです。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加