我试图定义这个函数来重新组合三个对列表:
{-# LANGUAGE RankNTypes #-}
mapAndZip3 :: (forall x. x -> f x) -> [a] -> [b] -> [c]
-> [(f a, f b, f c)]
mapAndZip3 f la lb lc = zipWith3 (\a b c -> (f a, f b, f c)) la lb lc
main = do
let x = mapAndZip3 (fst) [(1,"fruit"), (2,"martini")]
[("chips","fish"),("rice","steak")]
[(5,"cake"),(4,"pudding")]
print x -- was expecting [(1,"chips",5), (2,"rice",4)]
起初我没有包括RankNTypes
or forall
,但后来看到this,即liftTup
定义后,我认为它应该足够了。
但显然,它不是,因为我仍然得到一个错误:
mapAndZip3.hs:8:25:
Couldn't match type `x' with `(f0 x, b0)'
`x' is a rigid type variable bound by
a type expected by the context: x -> f0 x at mapAndZip3.hs:8:13
Expected type: x -> f0 x
Actual type: (f0 x, b0) -> f0 x
In the first argument of `mapAndZip3', namely `(fst)'
我显然对forall
关键字的理解有限,但据我所知,在这种情况下,它应该允许f
接受任何类型。我不明白的是:一旦在给定的上下文中使用一次,定义是否会在剩余的上下文中得到“固定”?
似乎不是这样,因为如果我用 Ints 替换“chips”和“rice”,编译器仍然会抱怨,所以我想我假设有问题(当然,如果我mapAndZip3
在后一种情况下删除了类型注释,一切正常,因为签名被简化为 mapAndZip3 :: (a -> t) -> [a] -> [a] -> [a] -> [(t, t, t)]
,但这不是我想要的)。
我也发现了这个问题,但不能确定这是否是同一个问题,因为我试图应用的函数不是id
,而是fst
,snd
实际上返回不同类型的函数(a -> b)
。