As per the comments, the usual method is to define a newtype
. Note that the syntax is much the same as defining a data
type, except that you use newtype
in place of data
and are only permitted one field. In particular, you need a constructor, which is frequently given the same name as the type:
newtype Op r a = Op (a -> r)
-- ^^ ^^ ^^^^^^^^
-- newtype constructor field
This has the effect of defining a type isomorphic to a -> r
but with the type parameter a
coming "last" in the full type Op r a
, which allows you to define a Contravariant
instance for Op r
. Note that you'll need to unwrap and wrap the constructor where appropriate:
instance Contravariant (Op r) where
contramap f (Op g) = Op (g . f)
For additional evidence that this is correct way to do it, note that the definitions in Data.Functor.Contravariant
from base
are already set up like this, except they've decided to use a field accessor 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)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…