If you're willing to work with a few compiler extensions, ExistentialQuantification solves your problem nicely.
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE StandaloneDeriving #-}
module VectorTest where
type PrimVector a = [(Int, a)]
data Vector = forall a . Show a => Vector (PrimVector a)
deriving instance Show Vector
query :: [Vector] -> [Vector] -- equal length
query vectors = map (filterIndex commonIndices) vectors
where
commonIndices = intersection [mapFst vector | vector <- vectors]
intersection :: [[Int]] -> [Int]
intersection = head -- dummy impl. (intersection of sorted vectors)
filterIndex :: [Int] -> Vector -> Vector
filterIndex indices (Vector vector) = -- sample inefficient implementation
Vector $ filter (\(idx, _) -> idx `elem` indices) vector
mapFst :: Vector -> [Int]
mapFst (Vector l) = map fst l
-- sample usage of query
main = putStrLn $ show $ query [Vector [(1, 12), (2, -2)],
Vector [(2, 17), (3, -10)]]
The StandaloneDeriving requirement can be removed if you write a manual Show instance for Vector, e.g.
instance Show Vector where
show (Vector v) = show v