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.

foldr::(a -> b -> b) -> b -> [a] -> b
foldr(++) "kk" ["dog", "cat"] // here is how to use foldr 

1. (a -> b -> b) is function with two arguments, e.g. ++:("dog" "kk") -> "dogkk"
   int f(int a, int b)                           // function in Java
   [](auto a, auto b) { return a + b;}           // lambda function in C++
2. b is the second argument,                     e.g. b = "kk"
3. [a] is the third argument,                    e.g. ["dog", "cat"]
4. last b is the output,                         e.g. "dotcatkk"

The signature of concatMap?
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"

=> 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"