2

の使い方を勉強しようと思っていますGHC.Generics。魅力的なトピックですが、難しいです。

ブログ エントリ24 日間の GHC 拡張機能: DeriveGenericを読みながら、値を取得してその をナビゲートする方法を学びましたRep。わかった。

しかし、ブログエントリBuilding data constructors with GHC Genericsを読んで、構築と値への変換の類似性を説明していRepて、困惑しました。 多く リソースを読みましたが、大きな助けにはなりませんでした。

ブログエントリには次のコードがあります。まず、以下を構築しRepます。

class Functor f => Mk rep f | rep -> f where
  mk :: f (rep a)

instance Mk (K1 i c) ((->) c) where
  mk = \x -> K1 x

instance (Mk l fl, Mk r fr) => Mk (l :*: r) (Compose fl fr) where
  mk = Compose (fmap (\l -> fmap (\r -> l :*: r) mk) mk)

instance (Mk f f') => Mk (M1 i c f) f' where
  mk = M1 <$> mk

次に、次の処理を行いComposeます。

class Functor f => Apply f a b | f a -> b where
  apply :: f a -> b

instance Apply ((->) a) b (a -> b) where
  apply = id

instance (Apply g a b, Apply f b c) => Apply (Compose f g) a c where
  apply (Compose x) = apply (fmap apply x)

次に、型のあいまいさを処理します。

type family Returns (f :: *) :: * where
  Returns (a -> b) = Returns b
  Returns r = r

make :: forall b f z. (Generic (Returns b), Apply f (Returns b) b, Mk (Rep (Returns b)) f) => b
make = apply (fmap (to :: Rep (Returns b) z -> (Returns b)) (mk :: f (Rep (Returns b) z)))

わお。

本当に、私はファンクタを返すクラスMkで、最初に立ち往生しています。mk私の質問:

  1. mk戻るとは何ですか?なぜファンクターなのですか?その結果の解釈は何ですか?のK1 i cインスタンスMkが、値を受け取って でラップする関数 (これはファンクタであることは理解しています) を返していることがわかりますK1mkMk (l :*: r)Mk (M1 i c f)は完全に失われています。

  2. Composeから来ていると推測しています。Data.Functor.Composeつまり、 を実行すると、構成されたファンクターの奥深くで 2 つのレベルが実行されます。しかし、 .内にネストされた s を理解できません。fmap f xfmapfmapCompose

  3. のインスタンスの場合M1 i c f、内部の値を でラップするだけだと思っていたので、またはM1の必要性は私には意味がありません。M1 <$> mkfmap M1 mk

明らかに、私はこれらのインスタンスの意図や意味、およびこれらのインスタンスがどのように相互作用して final を作成するかを理解しているわけではありませんRep。誰かが私を啓発しGHC.Generics、途中で使用する方法の良い説明を提供してくれることを願っています.

4

1 に答える 1