在ghci中执行以下代码:
import qualified Data.Map.Strict as Map
f = Map.fromList . zip
将给出以下错误:
<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)
我本来希望f是[a] -> [b] -> Map a b
类型的函数发生了什么事?
如果您用另一个函数组合zip
,则意味着您将其视为一个函数
zip::[a]->([b]->[(a,b(](
所以组成它的函数需要有一个类型为[b] -> [(a,b)]
的参数。但Map.fromList
的自变量只是[(a,b)]
的一部分,即它要求其他自变量也已经应用。
有几种方法可以解决这个问题:
-
以未压缩的形式使用函数。这具有您在这里所期望的行为,即
Map.fromList . uncurry zip
类型检查,但这意味着整个过程也将采用元组形式的列表参数,这有点被Haskellers 蔑视f :: Ord a => ([a], [b]) -> Map.Map a b f = Map.fromList . uncurry zip
当然,你可以"撤销">
f :: Ord a => [a] -> [b] -> Map.Map a b f = curry $ Map.fromList . uncurry zip
但这有点傻。
-
使用
fromList
的版本进行组合,该版本在另一个参数之后进行组合。这可以作为合成操作符的操作符部分来完成:f = (Map.fromList . ) . zip
同样的事情也可以通过利用
Functor (c->)
实例来实现f = fmap Map.fromList . zip
我不喜欢这两种。
-
只需让至少一个论点有针对性。
f keys = Map.fromList . zip keys
这就是我的建议。