What is concatMap in Haskell
  The signature of Haskell function is confusing and initimite, lets see an example
  If you see the signature of foldr with Java/C++ background, you would say WTF.


  The signature of concatMap?
  :i concatMap
  concatMap :: Foldable t =>(a -> [b]) -> t a -> [b]
  concatMap::(a -> [b]) -> [a] -> [b]

  concatMap f = foldr((++) . f)) []    // it seems to me concapMap is only for String
  Note: the implementaton of concapMap is not exactly like that in Haskell, but close

  -- map toUpper => "dog" => "DOG"
  -- concat $ ((map . map) toUpper) = concatMap ["dog", "cat"]
  --
  concatMap( map(toUpper) ) ["dog", "cat"] => "DOGCAT"
                   ↑
                   f
           apply f on each element inside ["dog", "cat"]
                             ↑
                           "dog"
        
           then concat the result

  => foldr((++) . map(toUpper)) [] ["dog", "cat"]     -- map toUpper => "dog" => "DOG"
  => foldr((++)) [] [map(toUpper) "dog", map(toUpper) "cat"]
  => foldr((++)) [] ["DOG", "CAT"]
  =>  "DOG" ++ ("CAT" ++ [])
  =>  "DOGCAT"

  or
  => foldr(++) [] $ (map . map) toUpper ["dog", "cat"]
  => foldr(++) [] ["DOG", "CAT"]
  =>  "DOGCAT"
Real world use case for concatMap
  concat $ map trim [" ", "b", " "] => "b"
  concatMap trim [" ", "b", " "] => "b"
  concatMap trim [" ", "", " "]  => []