在逆变函子的实例声明中删除类型同义词
如果我定义:
class Contravariant f where
contramap :: (b -> a) -> f a -> f b
type Op r a = (->) a r
并想定义:
instance Contravariant (Op r) where
contramap f g = g . f
我得到实例类型不能是同义词的错误。所以我想我需要类似的东西:
instance Contravariant ((->) _ r) where
contramap f g = g . f
这当然不起作用。我怎样才能让这个 Contravariant 实例工作?
回答
根据评论,通常的方法是定义一个newtype. 请注意,语法与定义data类型非常相似,只是您使用newtype代替data并且只允许使用一个字段。特别是,您需要一个构造函数,它经常被赋予与类型相同的名称:
newtype Op r a = Op (a -> r)
-- ^^ ^^ ^^^^^^^^
-- newtype constructor field
这具有定义与 to 同构的类型的效果,a -> r但类型参数a在完整 type 中“最后”出现Op r a,这允许您Contravariant为Op r. 请注意,您需要在适当的地方解包和包装构造函数:
instance Contravariant (Op r) where
contramap f (Op g) = Op (g . f)
有关更多的证据证明这是做正确的方法,注意定义在Data.Functor.Contravariant从base已经建立了这样的,除非他们已经决定使用字段访问getOp:
-- from the Data.Functor.Contravariant source
newtype Op a b = Op { getOp :: b -> a }
instance Contravariant (Op a) where
contramap f g = Op (getOp g . f)