[英]Turn adjacency list into tuple array Haskell
假設我輸入以下內容:
[(0, [1, 2]) , (2, [3, 4]) , (4, [])
這是一個鄰接表,我想這樣轉換它:
[(0,1), (0,2), (2,3), (2, 4)]
-注意沒有4
映射到任何東西
這是我到目前為止的內容:
conv :: [(Int, [Int])] -> [(Int, Int)]
conv adj = map fn adj -- mapping (0, [1, 2]) should give me [(0, 1), (0, 2)]
fn:: (Int, [Int]) -> [(Int, Int)]
fn (rt, list) = -- somehow perform [(rt, l[0]), (rt, l[1]) ...]
列表理解可以解決問題:
conv :: [(a, [b])] -> [(a, b)]
conv xys = [(x, y) | (x, ys) <- xys, y <- ys ]
或者我們可以在這里使用concatMap
:
conv :: Foldable f => f (a, [b]) -> [(a, b)]
conv = concatMap (uncurry (map . (,)))
在這里,內部函數uncurry (map . (,))
取一個元組(x, ys)
,從而執行一個map (x,)
: uncurry
基本上將其元組(x, ys)
uncurry
,然后調用(map . (,)) x ys
,這意味着我們獲得(map (x,)) ys
。 上面的語法使用了TupleSections
擴展,但是我們不需要在實際程序中激活該擴展,因為我們從不編寫這種語法。 因此,您定義的fn
函數等效於uncurry (map . (,))
。
因此,我們在concatMap
中使用此函數,該concatMap
將傳遞2個元組,並連接這些單個元組創建的列表。
或者我們可以使用“ bind” >>= :: Monad m => ma -> (a -> mb) -> mb
函數:
conv :: Monad m => m (a, m b) -> m (a, b)
conv = (=<<) (\(x, ys) -> ys >>= return . (x,))
或更短:
conv :: Monad m => m (a, m b) -> m (a, b)
conv = (=<<) (uncurry (fmap . (,)))
后者的好處是它也可以與Maybe
等等一起使用,例如:
Prelude> conv [(0, [1, 2]) , (2, [3, 4]) , (4, [])]
[(0,1),(0,2),(2,3),(2,4)]
Prelude> conv Nothing
Nothing
Prelude> conv (Just (3, Nothing))
Nothing
Prelude> conv (Just (3, Just 2))
Just (3,2)
利用instance Traversable ((,) a)
的instance Traversable ((,) a)
,我們得到了一個非常短的(而且非常難懂的)解決方案:
conv :: [(Int, [Int])] -> [(Int, Int)]
conv = (sequence =<<)
(sequence =<<)
的最一般類型是(Monad m, Traversable t) => m (t (ma)) -> m (ta)
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.