I need a function like Vector [Vector a] -> Vector [Vector a], where everything stays within the same list-index, but (for each list-index) the i-th element of the j-th inner-vector becomes the j-th element of the i-th inner-vector. I suspect I'm making this a lot harder than it needs to be.
I think I specifically want to use this implementation of fixed-length vectors, but I could consider other options.
I have it working on a stand-in Pair class I wrote for simplicity, but my implementation relies heavily on pattern-matching against the structure of Pair, in a way that I think won't work for a Vec n.
The Pair class is barely relevant; it's similar to Vec nat2, but I only implemented what I thought I'd need:
data Pair a where
Pair :: a -> a -> Pair a
deriving (Read, Show, Eq)
instance Functor Pair where
fmap f (Pair a1 a2) = Pair (f a1) (f a2)
instance Applicative Pair where
pure a = Pair a a
(Pair f1 f2) <*> (Pair a1 a2) = Pair (f1 a1) (f2 a2)
instance Foldable Pair where
foldr f b (Pair a1 a2) = a1 `f` (a2 `f` b)
(!) :: Pair a -> Bool -> a
(Pair a1 a2) ! b = if b then a2 else a1
universe :: Pair Bool
universe = Pair False True
Working code:
transpose :: Pair [Pair a] -> Pair [Pair a]
transpose (Pair b1s b2s) = t' b1s b2s
where t' ((Pair a11 a12) : a1s) ((Pair a21 a22) : a2s)
= Pair ((Pair a11 a21) :) ((Pair a12 a22) :) <*> t' a1s a2s
t' [] [] = pure []
-- A runtime error here is ok; I have external guarantees that this won't happen.
t' _ _ = error "Transposition requires the lists to be of equal length."
Example:
> let subject = Pair [
Pair (1, 1, 1) (1, 1, 2),
Pair (1, 2, 1) (1, 2, 2),
Pair (1, 3, 1) (1, 3, 2)
] [
Pair (2, 1, 1) (2, 1, 2),
Pair (2, 2, 1) (2, 2, 2),
Pair (2, 3, 1) (2, 3, 2)
]
> transpose subject
↠ Pair [
Pair (1,1,1) (2,1,1),
Pair (1,2,1) (2,2,1),
Pair (1,3,1) (2,3,1)
] [
Pair (1,1,2) (2,1,2),
Pair (1,2,2) (2,2,2),
Pair (1,3,2) (2,3,2)
]
With some struggle I can almost get an implementation that exclusively uses list/functor/applicative/index-able operators instead of pattern matching (and should therefore work for a Vec n), but I keep getting stuck.
How can I re-write my transpose function to work on some other structure like Pair, but with parametric size?