I was trying to define this function to regroup three lists of pairs:
{-# 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)]
At first I didn't include the RankNTypes
or the forall
, but then after seing this, namely the liftTup
definition, I thought that it should be enough.
But clearly, it wasn't, as I still get an error:
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)'
I clearly have a limited understanding of the forall
keyword, but from what I understood it should, in this case, allow for f
to accept any type. What I don't understand is: once within a given context, and used once, does the definition gets 'fixed' for the remaining context?
It doesn't seem so, because if I replace "chips" and "rice" with Ints, the compiler still complains, so I guess I'm assuming something wrong (of course, if I remove the type annotation of mapAndZip3
in this latter case, everything works out because the signature gets simplified to mapAndZip3 :: (a -> t) -> [a] -> [a] -> [a] -> [(t, t, t)]
, but this is not what I want).
I also found this question, but can't really make if this is the same problem or not, since the function I am trying to apply is not id
, but fst
or snd
, functions that actually return different types (a -> b)
.