A simple intuition for Functor is to see Functor as some kind of container and the ability to apply some function f to every element in the container without altering it's structure.

As an example, a list is a container of elements and we can apply a function to each element in the list without changing it's underlying structure.

There are many kinds of functor. Here we will explore

Covariant functor

This might also be thought of as the canonical Functor implementation.

Given a function of (a -> b) and a functor of a return a functor of b

class CovariantFunctor f where
    fmap :: (a -> b) -> f a -> f b

instance CovariantFunctor Maybe where
    fmap _ Nothing = Nothing
    fmap f (Just x) = Just (f x)

instance CovariantFunctor [] where
    fmap f []     = []
    fmap f (x:xs) = f x : fmap f xs
instance CovariantFunctor IO where
    fmap f x = x >>= return . f

Instances of the covariant functor should satisy two laws

fmap id == id

fmap (f . g) = fmap f . fmap g

Contravariant functor

Somtimes referred to as a cofunctor