# Functor: Mapping Inside a Context — Haskell

Source: https://www.geekswithgeeks.com/en/haskell/a-functor

> Understand fmap and the Functor laws with lists, Maybe, Either and your own types.

## fmap generalises map

Many types are **containers or contexts** around values: a list holds many values, `Maybe` holds zero or one, `Either e` holds a value or an error, `IO` will produce a value when run. The **`Functor`** class captures the ability to apply a function to the value(s) inside without changing the structure: `fmap :: Functor f => (a -> b) -> f a -> f b`, with the infix synonym **`<$>`**. `fmap (+1) (Just 2)` is `Just 3`, `fmap (+1) Nothing` is `Nothing`, `fmap length (Right "abc")` is `Right 3`, and `fmap` over `IO` transforms the result of an action. Instances must obey two **laws**: mapping `id` changes nothing (`fmap id = id`), and mapping a composition equals composing maps (`fmap (f . g) = fmap f . fmap g`). These laws guarantee `fmap` only transforms values and never adds, removes or reorders them. You can write instances for your own types, and GHC can derive them with `deriving Functor` (the `DeriveFunctor` extension, included in `GHC2021`). Related helpers: `<$` replaces values with a constant, and `void` discards a result.

## fmap over different contexts

The same function is applied inside a list, a Maybe and an Either, keeping their shape.

![Three containers of different shapes with small values inside, each passing under the same function arrow and coming out the same shape with transformed values.](assets/figures/haskell/section-4-map.svg) — Figure 4.1 — fmap preserves structure.

## Functor instances in action

Built-in functors and a derived instance for a tree.

```haskell
{-# LANGUAGE DeriveFunctor #-}

data Tree a = Leaf | Node (Tree a) a (Tree a)
  deriving (Show, Functor)

-- a hand-written instance would be:
-- instance Functor Tree where
--   fmap _ Leaf = Leaf
--   fmap f (Node l x r) = Node (fmap f l) (f x) (fmap f r)

fromList :: Ord a => [a] -> Tree a
fromList = foldr insert Leaf
  where
    insert x Leaf = Node Leaf x Leaf
    insert x t@(Node l y r)
      | x < y     = Node (insert x l) y r
      | x > y     = Node l y (insert x r)
      | otherwise = t

main :: IO ()
main = do
  print (fmap (* 2) [1, 2, 3 :: Int])                   -- [2,4,6]
  print ((+ 1) <$> Just (41 :: Int))                    -- Just 42
  print (length <$> (Right "abc" :: Either String String))   -- Right 3
  print (fmap show (fromList [3, 1, 2 :: Int]))         -- a Tree of Strings
  n <- length <$> getLine                               -- fmap over an IO action
  print n
```

## Gift wrapping

fmap is a helper who can change the gift inside any kind of wrapping (a box, an envelope, a bag that might be empty) without tearing the wrapping or changing how many gifts there are.

**Quiz:** What is `fmap (+1) Nothing`?

- [ ] Just 1
- [ ] An error
- [x] Nothing
- [ ] 1

*Answer:* Nothing. Mapping over Nothing leaves Nothing: there is no value to transform.
