轉置列表列表
注意到 zip
將列表元組轉換為元組列表,
ghci> uncurry zip ([1,2],[3,4])
[(1,3), (2,4)]
和 transpose
和 sequenceA
的型別之間的相似性,
-- transpose exchanges the inner list with the outer list
-- +---+-->--+-+
-- | | | |
transpose :: [[a]] -> [[a]]
-- | | | |
-- +-+-->--+---+
-- sequenceA exchanges the inner Applicative with the outer Traversable
-- +------>------+
-- | |
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
-- | |
-- +--->---+
我們的想法是使用 []
的 Traversable
和 Applicative
結構將 sequenceA
作為一種 n-ary zip
進行部署,將所有內部列表逐點拼湊在一起。
[]
的預設優先選擇Applicative
例項不適合我們使用 - 我們需要一個 zippy``Applicative
。為此,我們使用了 Control.Applicative
中的 ZipList
newtype。
newtype ZipList a = ZipList { getZipList :: [a] }
instance Applicative ZipList where
pure x = ZipList (repeat x)
ZipList fs <*> ZipList xs = ZipList (zipWith ($) fs xs)
現在我們通過遍歷 ZipList
Applicative
免費獲得 transpose
。
transpose :: [[a]] -> [[a]]
transpose = getZipList . traverse ZipList
ghci> let myMatrix = [[1,2,3],[4,5,6],[7,8,9]]
ghci> transpose myMatrix
[[1,4,7],[2,5,8],[3,6,9]]