How to do it...

  1. Use Stack to create a new project working-with-functors with the simple template:
        stack new working-with-functors simple
  1. Open src/Main.hs in the editor. We will use this file to demonstrate the usage of Functors.
  2. After initial module definition for Main, import the module that includes the Functor type class:
        import Data.Functor
  1. Define a function to square a number. We will use it to demonstrate application of this function over several data structures:
        -- Square a number
square :: Num a => a -> a
square x = x * x
  1. Functor f is a type class that needs  fmap :: (a -> b) -> f a -> f aData.Functor defines a function <$> synonymous to fmapList defines an instance for Functor. We will use a square function to apply over a list. Add the following code to get a square of all the elements in the list:
        -- Mapping a list
squareList :: Num a => [a] -> [a]
squareList xs = square <$> xs
  1. Similarly, we can use <$> to apply over Maybe and Either data types. Maybe allows a function to be applied if the data is represented with Just. Otherwise, a function is not applied. The Either instance for Functor allows a function to be applied only when the Right constructor is used:
        -- Mapping a Maybe
squareMaybe :: Num a => Maybe a -> Maybe a
squareMaybe x = square <$> x

-- Mapping an Either
squareEither :: Num a => Either c a -> Either c a
squareEither x = square <$> x
  1. Now, define a data type Function a b to represent a function a -> b. We will define this to be an instance of Functor. The Functor instance for this data type will create a composition by using the composition function (.)
        data Function a b = Function (a -> b)

instance Functor (Function a) where
f `fmap` (Function g) = Function (f . g)
  1. Define another utility function double to double a given value. We will use it in the main function to demonstrate the function's composition:
        double :: Num a => a -> a
double x = x + x
  1. Now, add the main function where we will put to test all the preceding definitions: 
        main :: IO ()
main = do
putStrLn "Mapping a list"
putStrLn $ show $ squareList [1..10]

putStrLn ""
putStrLn "Mapping Maybe"
putStrLn "Just 10 -> Just 100"
putStrLn $ show $ squareMaybe (Just 10)

putStrLn ""
putStrLn "Nothing -> Nothing"
putStrLn $ show $ squareMaybe Nothing

putStrLn ""
putStrLn "Mapping Either"
putStrLn "Right 10 -> Right 100"
putStrLn $ show $ squareEither (Right 10 :: Either String Int)
putStrLn "Left String -> Left String"
putStrLn $ show $ squareEither (Left "Left Value" ::
Either String Int)

let squareF = Function square
doubleSquare = double <$> squareF

-- Take the resultant function out of doubleSquare
let Function dsq = doubleSquare
putStrLn "Double the Square of X"
print $ dsq 10
  1. Build and run the project:
        stack build
stack exec -- working-with-functors
  1. The output should look like this: