executing the following Code in ghci:
import qualified Data.Map.Strict as Map
f = Map.fromList . zip
will give the following error:
<interactive>:16:20: error:
• Couldn't match type ‘[b0] -> [(a, b0)]’ with ‘[(k, a1)]’
Expected type: [a] -> [(k, a1)]
Actual type: [a] -> [b0] -> [(a, b0)]
• Probable cause: ‘zip’ is applied to too few arguments
In the second argument of ‘(.)’, namely ‘zip’
In the expression: Map.fromList . zip
In an equation for ‘f’: f = Map.fromList . zip
• Relevant bindings include
f :: [a] -> Map.Map k a1 (bound at <interactive>:16:1)
I would have expected f to a function of type [a] -> [b] -> Map a b
What's happening?
CodePudding user response:
If you compose zip
with another function it means you're considering it as a function
zip :: [a] -> ([b] -> [(a,b)])
So the function you compose it with would need to have an argument of type [b] -> [(a,b)]
. But the argument of Map.fromList
is only the [(a,b)]
part, i.e. it requires that the other argument also has been applied already.
There are a couple of ways around this:
Use the function in uncurried form. That has the behaviour you seem to have expected here – i.e.,
Map.fromList . uncurry zip
typechecks – however it means the whole thing will also take the list arguments in tuple form, which is kind of scorned upon by Haskellersf :: Ord a => ([a], [b]) -> Map.Map a b f = Map.fromList . uncurry zip
Of course you could “undo the uncurrying”
f :: Ord a => [a] -> [b] -> Map.Map a b f = curry $ Map.fromList . uncurry zip
but that's a bit silly.
Do the composition with the version of
fromList
that composes itself after another argument. This can be done as an operator section of the composition operator:f = (Map.fromList . ) . zip
The same thing can also be achieved by tapping into the
Functor (c->)
instancef = fmap Map.fromList . zip
I'm not a fan of either of these.
Simply make at least one of the arguments point-ful.
f keys = Map.fromList . zip keys
That's what I would recommend.