How to coerce functors applied to coercible arguments - haskell

Consider the following Haskell code:
import Data.Coerce
newtype Decorated s a = Decorated a
fancyFunction :: Ctx s => f (Decorated s a) -> r
fancyFunction = ...
instance Ctx s => SomeClass (Decorated s a)
myFunction :: Functor f => f a -> r
myFunction = fancyFunction . fmap coerce
I'd like to make myFunction faster by replacing fmap coerce with coerce. The rationale is that coerce behaves like id and one of the functor laws is fmap id = id.
The only way I can see of doing this is to add Coercible (f a) (f (Decorated s a)) to the context but it refers to s which is not referred to anywhere else. Even worse, if a is bound in a universal type, I cannot express the constraint. Is there a constraint I could express in terms of f only to let me use coerce to convert between f a and f (Decorated s a)?
Is this something that the compiler figures out on its own from the fact that f is a functor? If so, does it also work with bifunctors, traversables and bitraverables?

Unfortunately, Coercible (f a) (f (Decorated s a)) really what you want in your constraint given the current state of GHC. Now, the fact that s and a don't show up elsewhere is not something good - it means GHC won't know what to do with them (they are ambiguous)! I won't get into that...
Depending on the role of the type parameter fed to the type constructor f, Coercible a b may or may not imply Coercible (f a) (f b). In this case, we'd want that role to be nominal - but there isn't (yet at least) a way to express this in a constraint. To explain what I mean, consider the following two data definitions:
{-# LANGUAGE TypeFamilies #-}
import Data.Coerce
-- type role of `a` is "representational"
data Data1 a = Data1 a
-- type role of `a` is "nominal"
data Data2 a = Data2 (TypeFunction a)
type family TypeFunction x where
TypeFunction Bool = Char
TypeFunction _ = ()
Then, while it is true that Coercible a b entails Coercible (Data1 a) (Data1 b), it does not entail Coercible (Data2 a) (Data2 b). To make this concrete, load up the above in GHCi, then try:
ghci> newtype MyInt = My Int
ghci> let c1 = coerce :: (Data1 MyInt) -> (Data1 Int)
ghci> let c2 = coerce :: (Data2 MyInt) -> (Data2 Int) -- This doesn't work!
Unfortunately, there is no built-in constraint based way of enforcing that the role of a type variable is representational. You can make your own classes for this, as Edward Kmett has done, but GHC doesn't automatically create instances of some of these classes the way class instances for Coercible are.
This led to this trac ticket where they discuss the possibility of having a class Representational f with instances generated like for Coercible which could have things like
instance (Representational f, Coercible a b) => Coercible (f a) (f b)
If this was actually a thing today, all you would need in your constraint would be Representational f. Furthermore, as Richard Eisenberg observes on the ticket, we really ought to be able to figure out that a in f a has a representational role for any reasonable functor f. Then, we might not even need any constraint on top of Functor f as Representational could be a superclass of Functor.
Here is a good discussion of the current limitations of roles.

Now that you have QuantifiedConstraints, I think you can do this:
type Parametric f = (forall a b. (Coercible a b => Coercible (f a) (f b)) :: Constraint)
newtype Foo = Foo Int
myFunction :: (Parametric f) => f Foo -> f Int
myFunction = coerce
test :: [Int]
test = myFunction [Foo 1, Foo 2, Foo 3]
This is nice, because an instance of Parametric f witnesses that f is an endofunctor on a category where the objects are types and a morphism between types A and B is an instance of Coercible A B.

Related

Is it possible to derive a Traversable instance via another type constructor?

Suppose we have some class Foo such that an instance of Foo f gives us everything necessary to implement Functor f, Foldable f and Traversable f. To avoid overlapping instances, can witness this relationship between Foo and Functor, Foldable, Traversable under a newtype wrapper:
type Foo :: (Type -> Type) -> Constraint
class Foo f
where
{- ... -}
type FoonessOf :: (Type -> Type) -> Type -> Type
newtype FoonessOf f a = FoonessOf (f a)
instance Foo f => Functor (FoonessOf f)
where
fmap = _
instance Foo f => Foldable (FoonessOf f)
where
foldMap = _
instance Foo f => Traversable (FoonessOf f)
where
traverse = _
Now suppose we have some type constructor:
data Bar a = Bar {- ... -}
such that there is an:
instance Foo Bar
where
{- ... -}
We'd like to equip Bar with the instances implied by its "Foo-ness". Since Bar a is Coercible to FoonessOf Bar a, we'd expect to be able to derive the instances via the FoonessOf Bar:
deriving via (FoonessOf Bar) instance Functor Bar
deriving via (FoonessOf Bar) instance Foldable Bar
And this works handily for typeclasses such as Functor and Foldable
Unfortunately when we try to do the same thing with Traversable, things go awry:
[typecheck -Wdeferred-type-errors] [E] • Couldn't match representation of type ‘f1 (Foo Bar a1)’
with that of ‘f1 (Bar a1)’
arising from a use of ‘ghc-prim-0.6.1:GHC.Prim.coerce’
NB: We cannot know what roles the parameters to ‘f1’ have;
we must assume that the role is nominal
• In the expression:
ghc-prim-0.6.1:GHC.Prim.coerce
#(Foo Bar (f a) -> f (Foo Bar a)) #(Bar (f a) -> f (Bar a))
(sequenceA #(Foo Bar)) ::
forall (f :: TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep
-> TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep)
(a :: TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep).
Applicative f => Bar (f a) -> f (Bar a)
In an equation for ‘sequenceA’:
sequenceA
= ghc-prim-0.6.1:GHC.Prim.coerce
#(Foo Bar (f a) -> f (Foo Bar a)) #(Bar (f a) -> f (Bar a))
(sequenceA #(Foo Bar)) ::
forall (f :: TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep
-> TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep)
(a :: TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep).
Applicative f => Bar (f a) -> f (Bar a)
When typechecking the code for ‘sequenceA’
in a derived instance for ‘Traversable Bar’:
To see the code I am typechecking, use -ddump-deriv
In the instance declaration for ‘Traversable Bar’
——————————————————————————————————————————————————————————————————————————————
...
So the questions I have are:
Is it possible to come up with some other scheme for deriving-via the instance Traversable Bar?
Is it possible to come up with some modification of the Traversable class that can be derived via a newtype?
I suspect the answer to 1. is: no, the situation cannot be salvaged, and it is impossible to obtain an instance of Traversable using DerivingVia.
As far as 2. goes, it's useful to try and reproduce the problem in a simpler context. Consider the following:
-- Remember to turn on ScopedTypeVariables!
data A = A
newtype B = B A
a :: forall f. f A -> f A
a = id
b :: forall f. f B -> f B
b = coerce $ a #f
It seems like this should work, but alas:
[typecheck -Wdeferred-type-errors] [E] • Couldn't match representation of type ‘f A’ with that of ‘f B’
arising from a use of ‘coerce’
NB: We cannot know what roles the parameters to ‘f’ have;
we must assume that the role is nominal
• In the expression: coerce $ a #f
In an equation for ‘b’: b = coerce $ a #f
• Relevant bindings include
b :: f B -> f B
The problem has to do with the "roles" of type constructors' parameters, and the way role inference works. For our purposes, roles come in two varieties: "representational" and "non-representational". Also for our purposes, the difference between the two can be approximated to the following: a type constructor F :: Type -> Type has a parameter of a "representational" role if there is an instance of Representational F, where:
type Representational :: (Type -> Type) -> Constraint
type Representational f = forall x y. Coercible x y => Coercible (f x) (f y)
Otherwise, the parameter of F is non-representational.
The typechecker lets you annotate the roles of type parameters in various places (although strangely enough, not in the kind). Sadly, there is no way to annotate the roles of a higher kinded type variable. What we can do however is just ask for Representational f directly:
b' :: forall f. Representational f => f B -> f B
b' = coerce $ a #f
which now typechecks. This suggests a possible way to tweak the Traversable typeclass to make it derivable via coercions.
Now let's look at the type of the Traversable operation sequenceA:
class Traversable t
where
sequenceA :: forall f. Applicative f => forall a. t (f a) -> f (t a)
{- ... -}
NB: There's that pesky forall f again, meaning f is taken to have a type parameter of a nominal role.
What DerivingVia is going to do is attempt to coerce between:
sequenceA #T1 :: forall f. Applicative f => forall a. T1 (f a) -> f (T2 a)
and:
sequenceA #T2 :: forall f. Applicative f => forall a. T2 (f a) -> f (T2 a)
Despite T1 (FoonessOf Bar) and T2 (Bar) being "parametrically" coercible, this coercion will fail, because the coercion of the entire operation will decompose eventually to the coercion the typechecker complained about:
Couldn't match representation of type
‘f1 (Foo Bar a1)’
with that of
‘f1 (Bar a1)’
This doesn't work because of f's parameter being considered to have a nominal role, as we discussed.
As with our simplified example above, the fix is straightforward: just ask for Representational f:
type Traversable' :: (Type -> Type) -> Constraint
class Traversable' t
where
traverse :: (Representational f, Applicative f) => (a -> f b) -> t (f a) -> f (t b)
And now at last we can derive an instance of Traversable' via the FoonessOf Bar:
instance Foo f => Traversable' (FoonessOf f)
where
traverse = _
deriving via (FoonessOf Bar) instance Traversable' Bar

Enforcing parametricity on arguments

Using RankNTypes one can enforce various kinds of parametricity. For example, A id :: A:
newtype A = A { unA :: forall a. a -> a }
But how about cases where we only care about the parametricity of the function on its argument? For a specific kind of case, the following will work:
newtype X b = X { unX :: forall a. a -> (a, b) }
For example, X (\a -> (a, ())) :: X ().
I would like to understand how to (or whether one can) construct a parametricity test that works more generally for functions of the form \a -> (a, f a), where f may be constant (as above) or potentially parametric itself. This can't be accomplished with X. E.g., X (\a -> (a, id a)) is a type error. Can this be done?
Edit: I'd like to repose or elaborate on the question somewhat. Suppose we have a type of parameterized state transformers:
type PState i o a = i -> (a, o)
Suppose also that we are interested in statically enforcing that the a in an arbitrary m :: PState i o a does not depend on i in any way. In other words, is it possible to define a function f such that f m is well typed when m's value doesn't depend on the input (and in that case evaluates to m), and is not well typed otherwise?
You'll need to make an explicit type-level function to accomplish this. Normally quantified Type -> Type variables are actually assumed to be type constructors (injective functions), which is not sufficient here. But it is possible to have noninjective ones too, they're just called type families. The flip side to this is that you need some separate means of actually indexing which one you want, because type inference wouldn't work without that.
{-# LANGUAGE TypeFamilies, KindSignatures, EmptyDataDecls, TypeInType
, RankNTypes, UnicodeSyntax #-}
import Data.Kind
type family MyTyFun (f :: Type) (a :: Type) :: Type
newtype GState f = GState { unGS :: ∀ a . a -> (a, MyTyFun f a) }
data Af
type instance MyTyFun Af a = ()
type A = GState Af
data Xf b
type instance MyTyFun (Xf b) a = b
type X b = GState (Xf b)
data Wf
type instance MyTyFun Wf a = a
type W = GState Wf
> unGS (GState (\a -> (a, a)) :: W) 4
(4,4)

Quantified constraints vs. (closed) type families

I am trying to use this blogpost's approach to higher-kinded data without dangling Identity functors for the trival case together with quantified-constraint deriving:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE QuantifiedConstraints, StandaloneDeriving, UndecidableInstances #-}
module HKD2 where
import Control.Monad.Identity
type family HKD f a where
HKD Identity a = a
HKD f a = f a
data Result f = MkResult
{ foo :: HKD f Int
, bar :: HKD f Bool
}
deriving instance (forall a. Show a => Show (HKD f a)) => Show (Result f)
This results in the infuriatingly self-contradicting error message:
Could not deduce Show (HKD f a)
from the context: forall a. Show a => Show (HKD f a)
Is there a way to do this without being long-winded about it and doing
deriving instance (Show (HKD f Int), Show (HKD f Bool)) => Show (Result f)
?
tl;dr, gist: https://gist.github.com/Lysxia/7f955fe5f2024529ba691785a0fe4439
Boilerplate constraints
First, if the question is about avoiding repetitive code, this is mostly addressed by generics alone, without QuantifiedConstraints. The constraint (Show (HKD f Int), Show (HKD f Bool)) can be computed from the generic representation Rep (Result f). The generic-data package (disclaimer: that I wrote) implements this:
data Result f = MkResult (HKD f Int) (HKD f Bool)
deriving Generic
-- GShow0 and gshowsPrec from Generic.Data
instance GShow0 (Rep (Result f)) => Show (Result f) where
showsPrec = gshowsPrec
or with DerivingVia:
-- Generically and GShow0 from Generic.Data
deriving via Generically (Result f) instance GShow0 (Rep (Result f)) => Show (Result f)
Quantified constraints with type families
Nevertheless, the constraint (Show (HKD f Int), Show (HKD f Bool)) may be less than ideal for various reasons. The QuantifiedConstraints extension may seem to provide a more natural constraint forall x. Show (HKD f x):
it would entail the tuple (Show (HKD f Int), Show (HKD f Bool));
contrary to that tuple, it does not blow up in size when the record gets big, and does not leak the field types of Result as they may be subject to change.
Unfortunately, that constraint is actually not well-formed. The following GHC issue discusses the problem in detail: https://gitlab.haskell.org/ghc/ghc/issues/14840 I don't understand all of the reasons yet, but in brief:
Quantified constraints won't work directly with type families for the foreseeable future, for reasons both theoretical and practical;
But there is a workaround for most use cases.
A quantified constraint should be viewed as a sort of "local instance". The general rule then is that type families are not allowed in the head of any instance ("instance head" = the HEAD in the following instance ... => HEAD where). So forall a. Show (HKD f a) (viewed as a "local" instance Show (HKD f a)) is illegal.
Quantified constraint smuggler
The following solution is credited to Icelandjack (Source: this comment from the ticket linked earlier; thanks also to Ryan Scott for relaying it.)
We can define another class that's equivalent to Show (HKD f a):
class Show (HKD f a) => ShowHKD f a
instance Show (HKD f a) => ShowHKD f a
Now forall x. ShowHKD f x is a legal constraint that morally expresses the intended forall x. Show (HKD f x). But it's not at all obvious how to use it. For example, the following snippet fails to type check (note: we can easily ignore the ambiguity issues):
showHKD :: forall f. (forall x. ShowHKD f x) => HKD f Int -> String
showHKD = show
-- Error:
-- Could not deduce (Show (HKD f Int)) from the context (forall x. ShowHKD f x)
This is counterintuitive, because ShowHKD f x is equivalent to Show (HKD f x) which can of course be instantiated with Show (HKD f Int). So why is that rejected? The constraint solver reasons backwards: the use of show first requires a constraint Show (HKD f Int), but the solver is immediately stuck. It sees forall x. ShowHKD f x in the context, but there is no clue for the solver to know that it should instantiate x to Int. You should imagine that at this point, the constraint solver has no idea of any relationship between Show and ShowHKD. It just wants a Show constraint, and there is none in the context.
We can help the constraint solver as follows, by annotating the body of the function with the needed instantiation(s) of ShowHKD f x, here ShowHKD f Int:
showHKD :: forall f. (forall x. ShowHKD f x) => HKD f Int -> String
showHKD = show :: ShowHKD f Int => HKD f Int -> String
This annotation provides the constraint ShowHKD f Int to the body show, which in turn makes the superclass available Show (HKD f Int) so show can be immediately satisfied. On the other side, the annotation requires the constraint ShowHKD f Int from its context, which provides forall x. ShowHKD f x. Those constraints match, and that leads the constraint solver to instantiate x appropriately.
Deriving Show with quantified constraints
With this, we can implement Show with a quantified constraint, using generics to fill out the body, and with some annotations to instantiate the quantified constraint,
(ShowHKD f Int, ShowHKD f Bool):
instance (forall a. Show a => ShowHKD f a) => Show (Result f) where
showsPrec = gshowsPrec :: (ShowHKD f Int, ShowHKD f Bool) => Int -> Result f -> ShowS
As before, those constraints can be automated with generics, so the only thing that changes in this implementation from one type to another is the name Result:
instance (forall a. Show a => ShowHKD f a) => Show (Result f) where
showsPrec = gshowsPrec :: ShowHKDFields f (Rep (Result HKDTag)) => Int -> Result f -> ShowS
-- New definitions: ShowHKDFields and HKDTag; see gist at the end.
And with a bit more effort, we can have DerivingVia too:
deriving via GenericallyHKD Result f instance (forall a. Show a => ShowHKD f a) => Show (Result f)
-- New definition: GenericallyHKD; see gist.
Full gist: https://gist.github.com/Lysxia/7f955fe5f2024529ba691785a0fe4439
I don't think you can do such thing, but I could certainly be wrong. In your example you are missing an extra constraint Show (f a) in order for it to be complete:
deriving instance (forall a. (Show a, Show (f a)) =>
Show (HKD f a)) => Show (Result f)
But that would mean that Show instance for f a cannot depend on a, which can be true for specific f, but not in general.
Edit
But at the same time it is possible to write something like that without the TypeFamilies:
data Bar f = MkBar (f Int)
deriving instance (forall a . Show a => Show (f a)) => Show (Bar f)
So, I am not sure why GHC can't figure it out.
Edit 2
Here is an interesting observation, this compiles:
type family HKD f a where
-- HKD Identity a = a
HKD f Int = Int
HKD f a = f a
data Result f = MkResult
{ foo :: HKD f Int
, bar :: HKD f Bool
}
deriving instance (forall a. Show a => Show (f a)) => Show (Result f)
and works as expected:
λ> show $ MkResult 5 (Just True)
"MkResult {foo = 5, bar = Just True}"
So, it looks like matching on f somehow messes up the type checker.
Worth noting, that restricting to Show (HDK f a) even for the simplified example also gives the same compile time error as in the question:
deriving instance (forall a. Show a => Show (HKD f a)) => Show (Result f)

Switch order of arguments for instance declaration in Haskell

I want to make an instance declaration, but the free type variable is not the last variable. For example, I have a class declaration
class Poppable m where
tryPop :: m a -> Maybe (a, m a)
Now I want to make Q.PSQ (priority queue) an instance of Poppable. Specifically I want something like this:
instance (Ord p) => Poppable (\a -> Q.PSQ a p) where
tryPop = fmap (first Q.key) . Q.minView
However, this is not legal Haskell code. If the order of arguments to PSQ were switched, then I would have no problem:
instance (Ord p) => Poppable (Q.PSQ p) where
tryPop = fmap (first Q.key) . Q.minView
How do I switch the order of arguments for the instance declaration?
Now I could wrap PSQ with a newtype:
newtype PSQ'' a b = PSQ'' (Q.PSQ b a)
However this seems clunky to me because I have to constantly wrap/unwrap it. Is there an easier way?
*
I tried using data/type families, but both give errors.
(1) Using a data family declaration:
data family PSQ' a b
data instance PSQ' a b = PSQ b a
instance (Ord p) => Poppable (PSQ' p) where
tryPop = fmap (first Q.key) . Q.minView
However this gives the error
Couldn't match type `Q.PSQ a p0' with `PSQ' p a'
even though they can match by setting p=p0.
(2) Type families won't work either.
type family PSQ' a b where
PSQ' b a = Q.PSQ a b
gives
Illegal type synonym family application in instance: PSQ' p
Now I could wrap PSQ with a newtype:
newtype PSQ'' a b = PSQ'' (Q.PSQ b a)
However this seems clunky to me because I have to constantly wrap/unwrap it. Is there an easier way?
Nope, not really. You could, of course, write your Poppable class to make it match PSQ. And if you like, you can generalize your newtype to
newtype Flip f a b = Flip (f b a)
at which point you could write
instance Poppable (Flip Q.PSQ a)
but none of this will get rid of the underlying annoyance factor. There are reasons Haskell doesn't support this (apparently, it makes inference much harder, sometimes impossible, etc.), so you'll just have to deal with it.
P.S., that type synonym may be more useful poly-kinded, with {-# LANGUAGE PolyKinds #-}, where it ends up meaning
newtype Flip (f :: k1 -> k2 -> *) (a :: k2) (b :: k1) = Flip (f b a)
You could simply abandon parametricity and use a type family to project whichever argument correspond to the 'element type':
class Poppable q where
type Elem q
tryPop :: q -> Maybe (Elem q, q)
data PSQ a p = ...
instance Ord p => Poppable (PSQ a p) where
type Elem (PSQ a p) = a
tryPop = ...
Note this is a more general formulation, but it may be harder to work with.

instance of "Type constructed with type argument" need not be constructed with data of that type, in Haskell

In Haskell, a type constructor can take a type argument, of course.
A function a -> b, when looked at as a "type with a funny constructor name", has type (->) a b. That makes it a type constructor (->) with two arguments, a and b. This is frequently encountered in the "reader" pattern as in its Functor and Applicative instances:
instance Functor ((->) a) where
fmap = (.)
instance Applicative ((->) a) where
pure = const
(<*>) f g x = f x (g x)
When I first tried to understand uses of this instance, as in
fmap (+1) (*2) 3 (=== (+1) . (*2) $ 3 === 3*2+1 === 7)
my reaction was "Ok, (+1) has type Int -> Int, which is (->) Int Int, so that matches Functor.... but where is the Int? I make a Maybe Int by calling Just 1, but I don't ever make a (->) Int Int by applying anything to an Int. In fact, I destroy a ((->) Int Int) by applying it to an Int! (Yeah, there's Nothing, but that seems... degenerate.)"
This all works (of course), as long as I remember that just because a type is built from a constructor+argument, that doesn't mean its values are built from a correspondingly typed constructor+argument. And some of the most interesting and powerful (and tricky to understand) type constructors are like this ((->), Lens, Arrow, etc)
(OK, really it's Num a => a, not Int, but let's ignore that, not relevant)
Is there a name for this concept? What is the appropriate mental model for thinking about type constructors, without leaning on the misleading and disempowering crutch interpretation "Foo a is a structure Foo containing value(s) of type a)?
This concept is known as a contravariant functor, on in Haskell-speak a Contravariant type.
class Contravariant f where
contramap :: (b -> a) -> f a -> f b
-- compare
class Functor f where
fmap :: (a -> b) -> f a -> f b
More generally, we can think of type variables in a type as having contravariant or covariant nature (at its simplest). For instance, by default we have
newtype Reader t a = Reader (t -> a)
instance Functor (Reader t) where
fmap ab (Reader ta) = Reader (ab . ta)
Which indicates that the second type parameter to Reader is covariant, while if we reverse the order
newtype RevReader a t = RevReader (t -> a)
instance Contravariant (RevReader a) where
contramap st (RevReader ta) = RevReader (ta . st)
A useful intuition for Contravariant types is that they have the ability to consume zero, one, or many values of the contravariant parameter instead of containing zero, one, or many values of the covariant parameter like we often think of when considering Functors.
Combining these two notions is the Profunctor
class Profunctor p where
dimap :: (a -> b) -> (c -> d) -> p b c -> p a d
which, as we notice, demands that p is of kind * -> * -> * where the first type parameter is contravariant and the second covariant. This class well characterizes the (->) type constructor
instance Profuntor (->) where
dimap f g h = g . h . f
Again, if we think of contravariant type parameters as being consumed and covariant ones as being produced this is quite amenable of the typical intuition around (->) types.
A few more examples of types which contravariant parameters include Relation
newtype Relation t = Relation (t -> t -> Bool)
instance Contravariant Relation where
contramap g (Relation pred) = Relation $ \a b -> pred (g a) (g b)
Or Fold which represents a left fold as a data type
newtype Fold a b = Fold b (a -> Fold a b)
instance Profunctor Fold where
dimap f g (Fold b go) = Fold (g b) (go . f)
sumF :: Num a => Fold a a
sumF = go 0 where
go n = Fold n (\i -> go (n + i))
With Fold a b we see that it consumes an arbitrary number of a types to produce one b type.
Generally what we find is that while it's often the case that we have covariant and "container" (strictly positive) types where values of some type c a are produced from a constructor of type a -> c a and some filler values a, in general that doesn't hold. In particular we have covariant types like that, but also contravariant ones which are often processes which somehow consume values of their parameterized type variables, or even more exotic ones like phantom types which utterly ignore their type variables
newtype Proxy a = Proxy -- need no `a`, produce no `a`
-- we have both this instance
instance Functor Proxy where
fmap _ Proxy = Proxy
-- and this one, though both instances ignore the passed function
instance Contravariant Proxy where
contramap _ Proxy = Proxy
and... "nothing special" type variables which cannot have any sort of nature, usually because they're being used as both covariant and contravariant types.
data Endo a = Endo (a -> a)
-- no instance Functor Endo or Contravariant Endo, it needs to treat
-- the input `a` differently from the output `a` such as in
--
-- instance Profunctor (->) where
Finally, a type constructor which takes multiple arguments may have different natures for each argument. In Haskell, the final type parameter is usually treated specially, though.

Resources