Given:
class Contravariant (f :: * -> *) where
contramap :: (a -> b) -> f b -> f a
The following code is rejected. I'm expecting to get String -> Bool
(a predicate) as a result of contra-mapping Int -> Bool
over String -> Int
. I feel stupid as I must be making some wrong assumptions. Please help me in understanding the error message. Why is the second argument expected to be different than the one I think I need?
Prelude Control.Lens> contramap length (>0) "Hello"
<interactive>:25:19: error:
• Couldn't match type ‘Bool’ with ‘Int’
Expected type: [Char] -> Int
Actual type: [Char] -> Bool
• In the second argument of ‘contramap’, namely ‘(> 0)’
In the expression: contramap length (> 0) "Hello"
In an equation for ‘it’: it = contramap length (> 0) "Hello"
Contravariant only works on the last argument of a type constructor. You might want Profunctor
, which denotes type constructors that are contravariant in the second to last argument and covariant (like a regular Functor) in the last one.
<Gurkenglas> > lmap length (>0) "hello"
<lambdabot> True
Actually, you're looking for the boring old covariant Functor
instance.
> fmap (>0) length "Hello"
True
At an even higher level, you may be looking for the null
function. For many types, length
will traverse the entire data structure you pass to it, whereas null
generally will not.
Here is a short explanation of the error message, as well. First:
contramap length :: (Contravariant f, Foldable t) => f Int -> f (t a)
(>0) :: (Num a, Ord a) => (->) a Bool
I have aligned things in what I hope is a suggestive way. In order to apply contramap length
to (>0)
, we would need to set f ~ (->) a
and Int ~ Bool
. The second is clearly impossible, so the compiler complains. (N.B. The first equation is only subtly impossible; even if you supplied a function which returned an Int
you'd have a problem, but the compiler doesn't notice yet because the obvious problem with the second equation trumps it. Namely: there is no Contravariant
instance for (->) a
, and can't be!)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With