7

IDFunctorがうまく機能する簡単な例を次に示します。

newtype R a = R a

instance Functor R where
    fmap f (R a) = R $ f a

しかし、中間型族を追加すると、物事が不安定になります。

data IntT
data a :-> b

type family   Sem a         :: *
type instance Sem IntT      = Int
type instance Sem (a :-> b) = Sem a -> Sem b

newtype S a = S (Sem a)

そして今、私はSをファンクターにすることができません。ファンクターのようなものの新しいクラスを簡単に定義できますが、アプリケーションのようなものとモナドのようなもののクラスも必要になり、それは不幸な道のように思えます。特にとして

smap f (S a) = S $ f a

実際に私が望むタイプ、すなわちsmap :: (Sem a -> Sem b) -> S a -> S b。しかし、もちろん、これはファンクターのタイプではありません。(「同じ」コードに2つの異なる互換性のないタイプがある場合、それを嫌いではありませんか?)

Data.Category.FunctorGenerics.Pointless.Functorsを調べましたが、どちらも私の問題を完全に解決しているようには見えませんでした。 PointlessTypeFamiliesにはさらに良いアイデアがあるように見えましたが、それでも、これからファンクターのようなものを十分に引き出す方法がわかりません。

のコードはforのコードと同じですが、何が起こっているのかが少し異なることに気づきましたある意味で、からへの自然変換があった場合、どういうわけかそれを持ち上げて取得できるはずです。その時点で、私はここで尋ねたほうがいいと思いました。それは私にかなりのトラブルを救うかもしれません!smapfmapRSemSsmap

4

1 に答える 1

3

このような状況に遭遇すると、通常、次のようなものに切り替えます。

data S b = forall a. S (a -> b) (Sem a)

これは簡単に法を遵守することができますFunctor

instance Functor S where
  fmap f (S g s) = S (f . g) s

またはCoyoneda、その動作をパッケージ化するために頼ります。

于 2012-11-16T17:59:59.463 に答える