Those are my first explorations in Haskell, so pardon me if it should be obvious.
I have been playing all afternoon with Haskell, sifting through the tutorial 99 questions on HaskellWiki, using my own list type (typical Cons). I've added "obvious" functions as I went on, and I have tried to make them as concise as possible (employing point-free notation whenever possible)
The 12th problem is about decoding a run-length encoded list, that is:
> decode [Multiple 5 'a', Single 'b', Multiple 2 'c']
"aaaaabcc"
And I thought about using map
to decode each element, then concat
the result (thanks Google on this), and finally remembered that I had seen something like concatMap
in my readings, which GHCi quickly confirmed:
> :t map
map :: (a -> b) -> [a] -> [b]
> :t concat
concat :: [[a]] -> [a]
> :t concatMap
concatMap :: (a -> [b]) -> [a] -> [b]
It looked like it would be obvious to reimplement concatMap
:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap = concat . map
Except that GHCi quite complains:
List.hs:110:15:
Couldn't match expected type `[a] -> [b]'
with actual type `[a0]'
Expected type: [[a0]] -> [a] -> [b]
Actual type: [[a0]] -> [[a0]]
In the first argument of `(.)', namely `concat'
In the expression: concat . map
I could not figure it out, so I looked up on the web, and the definition referenced in Prelude is actually:
concatMap f = concat . map f
And I don't quite understand why this f is necessary, since it's type is obviously a -> [b]
as specified by the signature...
So why is f
necessary here ?