I would like understand, why for example, the Maybe
type is a covariant functor?
What does covariant mean?
Please provide an example to clarify.
A covariant functor is just the normal Functor
class:
class Functor f where
fmap :: (a -> b) -> f a -> f b
For instance, Maybe
(as you noted):
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
However, there is another type of functor: contravariant functors. These are defined as follows:
class Contravariant f where
contramap :: (a -> b) -> f b -> f a
Note that compared to fmap
, contramap
has reversed the order of b
and a
:
fmap :: Functor f => (a -> b) -> f a -> f b
contramap :: Contravariant f => (a -> b) -> f b -> f a
-- ^ ^
-- look!
Now, does this crazy Contravariant
class even have any instances? Well, yes. For example, here's the definition of a Predicate
:
newtype Predicate x = Predicate { decide :: x -> Bool }
In other words, a Predicate x
is a function which calculates a condition on an x
. We can specialise contramap
to Predicate
s:
contramap :: (a -> b) -> Predicate b -> Predicate a
Which is equivalent to:
contramap :: (a -> b) -> (b -> Bool) -> (a -> Bool)
Basically, given a Predicate
on b
s, and a mapping from a
s to b
s, you can contramap
to get a Predicate
on a
s. (I'll leave the implementation as an exercise.) Here's an example (untested):
hasMultChars :: Predicate String
hasMultChars = Predicate $ \x -> length x > 1
showInt :: Int -> String
showInt = show
intHasMultChars :: Predicate Int
intHasMultChars = contramap showInt hasMultChars
As it turns out, contravariant functors are a lot less common - and so a lot less useful - than normal covariant functors. So in practise, we leave out the 'covariant', since it doesn't add anything in most cases.
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