以下是身份Functor运行良好的简单示例:
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变成Functor。我可以很容易地定义一类类似类似Functor的东西,但是我还需要一类类似Applicative和Monad的东西,这似乎是一条不愉快的道路。特别是
smap f (S a) = S $ f a
实际上有我想要的类型,即smap :: (Sem a -> Sem b) -> S a -> S b
。但是,当然,这不是Functor的类型。 (当“相同”代码有两种不同的不兼容类型时,你不是只讨厌它吗?)
我已经探讨了Data.Category.Functor以及Generics.Pointless.Functors,但似乎也没有完全解决我的问题。 PointlessTypeFamilies似乎有更好的想法,但我仍然不确定如何从中得到足够类似Functor的东西。
已告诉我,即使smap
的代码与fmap
R
的代码相同,但发生的情况略有不同。在某种程度上,如果我有Sem
到S
的自然转换,那么我应该能够解除它以获得smap
。在那一点上,我想我不妨在这里问一下,这可能会给我带来很多麻烦!
答案 0 :(得分: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
为我打包行为。