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 ?
Starting with the standard definition,
concat . map f
≡ concat . (map f)
≡ \x -> concat ((map f) x)
Your first definition gives you:
(concat . map) f
≡ (\x -> concat (map x)) f
≡ concat (map f)
which doesn't type check because (map f) :: [a] -> [b], while concat takes [[a]], a list of lists.
Note the particular error message shown in the question doesn't describe the above type-check failure. The given message arises from declaring the return type concatMap as [a] -> [b], which isn't reconcilable with [a0], the return type of concat. If you leave off the type signature, the response is:
Couldn't match type ‘[a1] -> [b]’ with ‘[[a]]’
Expected type: (a1 -> b) -> [[a]]
Actual type: (a1 -> b) -> [a1] -> [b]
Relevant bindings include
concatMap :: (a1 -> b) -> [a] (bound at :49:5)
Probable cause: ‘map’ is applied to too few arguments
In the second argument of ‘(.)’, namely ‘map’
In the expression: concat . map
Here, the type error occurs when reconciling the return type of map with the argument type of concat. It turns out this case is more useful for debugging as it contains a hint why the type check failed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With