在逆变函子的实例声明中删除类型同义词

如果我定义:

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,这允许您ContravariantOp r. 请注意,您需要在适当的地方解包和包装构造函数:

instance Contravariant (Op r) where
  contramap f (Op g) = Op (g . f)

有关更多的证据证明这是做正确的方法,注意定义在Data.Functor.Contravariantbase已经建立了这样的,除非他们已经决定使用字段访问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)


以上是在逆变函子的实例声明中删除类型同义词的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>